Path: blob/master/editor/shader/visual_shader_editor_plugin.cpp
21005 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/input/input.h"34#include "core/io/resource_loader.h"35#include "core/math/math_defs.h"36#include "core/os/keyboard.h"37#include "core/version_generated.gen.h"38#include "editor/docks/filesystem_dock.h"39#include "editor/docks/inspector_dock.h"40#include "editor/editor_node.h"41#include "editor/editor_string_names.h"42#include "editor/editor_undo_redo_manager.h"43#include "editor/file_system/editor_paths.h"44#include "editor/gui/editor_toaster.h"45#include "editor/gui/filter_line_edit.h"46#include "editor/inspector/editor_properties_vector.h"47#include "editor/scene/curve_editor_plugin.h"48#include "editor/scene/material_editor_plugin.h"49#include "editor/settings/editor_settings.h"50#include "editor/shader/shader_editor_plugin.h"51#include "editor/themes/editor_scale.h"52#include "editor/themes/editor_theme_manager.h"53#include "scene/animation/tween.h"54#include "scene/gui/button.h"55#include "scene/gui/check_box.h"56#include "scene/gui/code_edit.h"57#include "scene/gui/color_picker.h"58#include "scene/gui/flow_container.h"59#include "scene/gui/graph_edit.h"60#include "scene/gui/menu_button.h"61#include "scene/gui/option_button.h"62#include "scene/gui/popup.h"63#include "scene/gui/rich_text_label.h"64#include "scene/gui/separator.h"65#include "scene/gui/split_container.h"66#include "scene/gui/texture_rect.h"67#include "scene/gui/tree.h"68#include "scene/gui/view_panner.h"69#include "scene/main/window.h"70#include "scene/resources/curve_texture.h"71#include "scene/resources/sky.h"72#include "scene/resources/style_box_flat.h"73#include "scene/resources/visual_shader_nodes.h"74#include "scene/resources/visual_shader_particle_nodes.h"75#include "servers/display/display_server.h"76#include "servers/rendering/shader_preprocessor.h"77#include "servers/rendering/shader_types.h"7879struct FloatConstantDef {80String name;81float value = 0;82const char *desc_key;83};8485static FloatConstantDef float_constant_defs[] = {86{ "E", Math::E, TTRC("E constant (2.718282). Represents the base of the natural logarithm.") },87{ "Epsilon", CMP_EPSILON, TTRC("Epsilon constant (0.00001). Smallest possible scalar number.") },88{ "Phi", 1.618034f, TTRC("Phi constant (1.618034). Golden ratio.") },89{ "Pi/4", Math::PI / 4, TTRC("Pi/4 constant (0.785398) or 45 degrees.") },90{ "Pi/2", Math::PI / 2, TTRC("Pi/2 constant (1.570796) or 90 degrees.") },91{ "Pi", Math::PI, TTRC("Pi constant (3.141593) or 180 degrees.") },92{ "Tau", Math::TAU, TTRC("Tau constant (6.283185) or 360 degrees.") },93{ "Sqrt2", Math::SQRT2, TTRC("Sqrt2 constant (1.414214). Square root of 2.") }94};9596constexpr int MAX_FLOAT_CONST_DEFS = std_size(float_constant_defs);9798///////////////////99100void VisualShaderNodePlugin::set_editor(VisualShaderEditor *p_editor) {101vseditor = p_editor;102}103104Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {105Object *ret = nullptr;106GDVIRTUAL_CALL(_create_editor, p_parent_resource, p_node, ret);107return Object::cast_to<Control>(ret);108}109110void VisualShaderNodePlugin::_bind_methods() {111GDVIRTUAL_BIND(_create_editor, "parent_resource", "visual_shader_node");112}113114///////////////////115116void VSGraphNode::_draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color, const Color &p_rim_color) {117Ref<Texture2D> port_icon = p_left ? get_slot_custom_icon_left(p_slot_index) : get_slot_custom_icon_right(p_slot_index);118119Point2 icon_offset;120if (port_icon.is_null()) {121port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));122}123124icon_offset = -port_icon->get_size() * 0.5;125126// Draw "shadow"/outline in the connection rim color.127draw_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);128draw_texture_rect(port_icon, Rect2(p_pos + icon_offset * EDSCALE, port_icon->get_size() * EDSCALE), false, p_color);129}130131void VSGraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {132Color rim_color = get_theme_color(SNAME("connection_rim_color"), SNAME("GraphEdit"));133_draw_port(p_slot_index, p_pos, p_left, p_color, rim_color);134}135136///////////////////137138void VSRerouteNode::_notification(int p_what) {139switch (p_what) {140case NOTIFICATION_READY: {141connect(SceneStringName(mouse_entered), callable_mp(this, &VSRerouteNode::_on_mouse_entered));142connect(SceneStringName(mouse_exited), callable_mp(this, &VSRerouteNode::_on_mouse_exited));143} break;144case NOTIFICATION_DRAW: {145Vector2 offset = Vector2(0, -16 * EDSCALE);146Color drag_bg_color = get_theme_color(SNAME("drag_background"), SNAME("VSRerouteNode"));147draw_circle(get_size() * 0.5 + offset, 16 * EDSCALE, Color(drag_bg_color, selected ? 1 : icon_opacity), true, -1, true);148149Ref<Texture2D> icon = get_editor_theme_icon(SNAME("ToolMove"));150Point2 icon_offset = -icon->get_size() * 0.5 + get_size() * 0.5 + offset;151draw_texture(icon, icon_offset, Color(1, 1, 1, selected ? 1 : icon_opacity));152} break;153}154}155156void VSRerouteNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Color &p_color) {157Color rim_color = selected ? get_theme_color("selected_rim_color", "VSRerouteNode") : get_theme_color("connection_rim_color", "GraphEdit");158_draw_port(p_slot_index, p_pos, p_left, p_color, rim_color);159}160161VSRerouteNode::VSRerouteNode() {162Label *title_lbl = Object::cast_to<Label>(get_titlebar_hbox()->get_child(0));163title_lbl->hide();164165const Size2 size = Size2(32, 32) * EDSCALE;166167Control *slot_area = memnew(Control);168slot_area->set_custom_minimum_size(size);169slot_area->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);170add_child(slot_area);171172// Lay the input and output ports on top of each other to create the illusion of a single port.173add_theme_constant_override("port_h_offset", size.width / 2);174}175176void VSRerouteNode::set_icon_opacity(float p_opacity) {177icon_opacity = p_opacity;178queue_redraw();179}180181void VSRerouteNode::_on_mouse_entered() {182Ref<Tween> tween = create_tween();183tween->tween_method(callable_mp(this, &VSRerouteNode::set_icon_opacity), 0.0, 1.0, FADE_ANIMATION_LENGTH_SEC);184}185186void VSRerouteNode::_on_mouse_exited() {187Ref<Tween> tween = create_tween();188tween->tween_method(callable_mp(this, &VSRerouteNode::set_icon_opacity), 1.0, 0.0, FADE_ANIMATION_LENGTH_SEC);189}190191///////////////////192193VisualShaderGraphPlugin::VisualShaderGraphPlugin() {194vs_msdf_fonts_theme.instantiate();195}196197void VisualShaderGraphPlugin::_bind_methods() {198ClassDB::bind_method("add_node", &VisualShaderGraphPlugin::add_node);199ClassDB::bind_method("remove_node", &VisualShaderGraphPlugin::remove_node);200ClassDB::bind_method("connect_nodes", &VisualShaderGraphPlugin::connect_nodes);201ClassDB::bind_method("disconnect_nodes", &VisualShaderGraphPlugin::disconnect_nodes);202ClassDB::bind_method("set_node_position", &VisualShaderGraphPlugin::set_node_position);203ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);204ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);205ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);206ClassDB::bind_method("set_parameter_name", &VisualShaderGraphPlugin::set_parameter_name);207ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression);208ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve);209ClassDB::bind_method("update_curve_xyz", &VisualShaderGraphPlugin::update_curve_xyz);210ClassDB::bind_method(D_METHOD("attach_node_to_frame", "type", "id", "frame"), &VisualShaderGraphPlugin::attach_node_to_frame);211ClassDB::bind_method(D_METHOD("detach_node_from_frame", "type", "id"), &VisualShaderGraphPlugin::detach_node_from_frame);212ClassDB::bind_method(D_METHOD("set_frame_color_enabled", "type", "id", "enabled"), &VisualShaderGraphPlugin::set_frame_color_enabled);213ClassDB::bind_method(D_METHOD("set_frame_color", "type", "id", "color"), &VisualShaderGraphPlugin::set_frame_color);214ClassDB::bind_method(D_METHOD("set_frame_autoshrink_enabled", "type", "id", "enabled"), &VisualShaderGraphPlugin::set_frame_autoshrink_enabled);215}216217void VisualShaderGraphPlugin::set_editor(VisualShaderEditor *p_editor) {218editor = p_editor;219}220221void VisualShaderGraphPlugin::register_shader(VisualShader *p_shader) {222visual_shader = Ref<VisualShader>(p_shader);223}224225void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connection> &p_connections) {226connections = p_connections;227}228229void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid) {230if (editor->get_current_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {231Link &link = links[p_node_id];232233for (const KeyValue<int, Port> &E : link.output_ports) {234if (E.value.preview_button != nullptr) {235E.value.preview_button->set_pressed(false);236}237}238bool is_dirty = link.preview_pos < 0;239240if (!is_dirty && link.preview_visible && link.preview_box != nullptr) {241link.graph_element->remove_child(link.preview_box);242memdelete(link.preview_box);243link.preview_box = nullptr;244link.graph_element->reset_size();245link.preview_visible = false;246}247248if (p_port_id != -1 && link.output_ports[p_port_id].preview_button != nullptr) {249if (is_dirty) {250link.preview_pos = link.graph_element->get_child_count();251}252253VBoxContainer *vbox = memnew(VBoxContainer);254link.graph_element->add_child(vbox);255link.graph_element->move_child(vbox, link.preview_pos);256257GraphNode *graph_node = Object::cast_to<GraphNode>(link.graph_element);258if (graph_node) {259graph_node->set_slot_draw_stylebox(vbox->get_index(false), false);260}261262Control *offset = memnew(Control);263offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));264vbox->add_child(offset);265266VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);267port_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);268port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);269vbox->add_child(port_preview);270link.preview_visible = true;271link.preview_box = vbox;272link.output_ports[p_port_id].preview_button->set_pressed(true);273}274}275}276277void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, int p_node_id) {278callable_mp(this, &VisualShaderGraphPlugin::update_node).call_deferred(p_type, p_node_id);279}280281void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) {282if (p_type != editor->get_current_shader_type() || !links.has(p_node_id)) {283return;284}285remove_node(p_type, p_node_id, true);286add_node(p_type, p_node_id, true, true);287288// TODO: Restore focus here?289}290291void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, const Variant &p_value) {292if (p_type != editor->get_current_shader_type() || !links.has(p_node_id)) {293return;294}295296Button *button = links[p_node_id].input_ports[p_port_id].default_input_button;297298switch (p_value.get_type()) {299case Variant::COLOR: {300button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);301302Callable ce = callable_mp(editor, &VisualShaderEditor::_draw_color_over_button);303if (!button->is_connected(SceneStringName(draw), ce)) {304button->connect(SceneStringName(draw), ce.bind(button, p_value));305}306} break;307case Variant::BOOL: {308button->set_text(((bool)p_value) ? "true" : "false");309} break;310case Variant::INT:311case Variant::FLOAT: {312button->set_text(String::num(p_value, 4));313} break;314case Variant::VECTOR2: {315Vector2 v = p_value;316button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3));317} break;318case Variant::VECTOR3: {319Vector3 v = p_value;320button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3));321} break;322case Variant::VECTOR4: {323Vector4 v = p_value;324button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3) + "," + String::num(v.w, 3));325} break;326default: {327}328}329}330331void VisualShaderGraphPlugin::set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {332if (editor->get_current_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].parameter_name != nullptr) {333links[p_node_id].parameter_name->set_text(p_name);334}335}336337void VisualShaderGraphPlugin::update_curve(int p_node_id) {338if (links.has(p_node_id) && links[p_node_id].curve_editors[0]) {339Ref<VisualShaderNodeCurveTexture> tex = Object::cast_to<VisualShaderNodeCurveTexture>(links[p_node_id].visual_node);340ERR_FAIL_COND(tex.is_null());341342if (tex->get_texture().is_valid()) {343links[p_node_id].curve_editors[0]->set_curve(tex->get_texture()->get_curve());344}345tex->emit_changed();346}347}348349void VisualShaderGraphPlugin::update_curve_xyz(int p_node_id) {350if (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]) {351Ref<VisualShaderNodeCurveXYZTexture> tex = Object::cast_to<VisualShaderNodeCurveXYZTexture>(links[p_node_id].visual_node);352ERR_FAIL_COND(tex.is_null());353354if (tex->get_texture().is_valid()) {355links[p_node_id].curve_editors[0]->set_curve(tex->get_texture()->get_curve_x());356links[p_node_id].curve_editors[1]->set_curve(tex->get_texture()->get_curve_y());357links[p_node_id].curve_editors[2]->set_curve(tex->get_texture()->get_curve_z());358}359tex->emit_changed();360}361}362363int VisualShaderGraphPlugin::get_constant_index(float p_constant) const {364for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {365if (Math::is_equal_approx(p_constant, float_constant_defs[i].value)) {366return i + 1;367}368}369return 0;370}371372void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression) {373if (p_type != editor->get_current_shader_type() || !links.has(p_node_id) || !links[p_node_id].expression_edit) {374return;375}376links[p_node_id].expression_edit->set_text(p_expression);377}378379void VisualShaderGraphPlugin::attach_node_to_frame(VisualShader::Type p_type, int p_node_id, int p_frame_id) {380if (p_type != editor->get_current_shader_type() || !links.has(p_node_id) || !links.has(p_frame_id)) {381return;382}383384GraphEdit *graph = editor->graph;385if (!graph) {386return;387}388389// Get the hint label and hide it before attaching the node to prevent resizing issues with the frame.390GraphFrame *frame = Object::cast_to<GraphFrame>(links[p_frame_id].graph_element);391ERR_FAIL_COND_MSG(!frame, "VisualShader node to attach to is not a frame node.");392393Label *frame_hint_label = Object::cast_to<Label>(frame->get_child(0, false));394if (frame_hint_label) {395frame_hint_label->hide();396}397398graph->attach_graph_element_to_frame(itos(p_node_id), itos(p_frame_id));399}400401void VisualShaderGraphPlugin::detach_node_from_frame(VisualShader::Type p_type, int p_node_id) {402GraphEdit *graph = editor->graph;403if (!graph) {404return;405}406407const StringName node_name = itos(p_node_id);408GraphFrame *frame = graph->get_element_frame(node_name);409if (!frame) {410return;411}412413graph->detach_graph_element_from_frame(node_name);414415bool no_more_frames_attached = graph->get_attached_nodes_of_frame(frame->get_name()).is_empty();416417if (no_more_frames_attached) {418// Get the hint label and show it.419Label *frame_hint_label = Object::cast_to<Label>(frame->get_child(0, false));420ERR_FAIL_COND_MSG(!frame_hint_label, "Frame node does not have a hint label.");421422frame_hint_label->show();423}424}425426void VisualShaderGraphPlugin::set_frame_color_enabled(VisualShader::Type p_type, int p_node_id, bool p_enable) {427GraphEdit *graph = editor->graph;428ERR_FAIL_COND(!graph);429430const NodePath node_name = itos(p_node_id);431GraphFrame *frame = Object::cast_to<GraphFrame>(graph->get_node_or_null(node_name));432if (!frame) {433return;434}435436frame->set_tint_color_enabled(p_enable);437}438439void VisualShaderGraphPlugin::set_frame_color(VisualShader::Type p_type, int p_node_id, const Color &p_color) {440GraphEdit *graph = editor->graph;441ERR_FAIL_COND(!graph);442443const NodePath node_name = itos(p_node_id);444GraphFrame *frame = Object::cast_to<GraphFrame>(graph->get_node_or_null(node_name));445if (!frame) {446return;447}448449frame->set_tint_color(p_color);450}451452void VisualShaderGraphPlugin::set_frame_autoshrink_enabled(VisualShader::Type p_type, int p_node_id, bool p_enable) {453GraphEdit *graph = editor->graph;454ERR_FAIL_COND(!graph);455456const NodePath node_name = itos(p_node_id);457GraphFrame *frame = Object::cast_to<GraphFrame>(graph->get_node_or_null(node_name));458if (!frame) {459return;460}461462frame->set_autoshrink_enabled(p_enable);463}464465void VisualShaderGraphPlugin::update_reroute_nodes() {466for (const KeyValue<int, Link> &E : links) {467Ref<VisualShaderNodeReroute> reroute_node = Object::cast_to<VisualShaderNodeReroute>(E.value.visual_node);468if (reroute_node.is_valid()) {469update_node(editor->get_current_shader_type(), E.key);470}471}472}473474Ref<Script> VisualShaderGraphPlugin::get_node_script(int p_node_id) const {475if (!links.has(p_node_id)) {476return Ref<Script>();477}478479Ref<VisualShaderNodeCustom> custom = Ref<VisualShaderNodeCustom>(links[p_node_id].visual_node);480if (custom.is_valid()) {481return custom->get_script();482}483484return Ref<Script>();485}486487void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) {488links[p_node_id].input_ports.insert(p_port_id, { p_button });489}490491void VisualShaderGraphPlugin::register_expression_edit(int p_node_id, CodeEdit *p_expression_edit) {492links[p_node_id].expression_edit = p_expression_edit;493}494495void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor) {496links[p_node_id].curve_editors[p_index] = p_curve_editor;497}498499void VisualShaderGraphPlugin::update_parameter_refs() {500for (KeyValue<int, Link> &E : links) {501VisualShaderNodeParameterRef *ref = Object::cast_to<VisualShaderNodeParameterRef>(E.value.visual_node);502if (ref) {503remove_node(E.value.type, E.key, true);504add_node(E.value.type, E.key, true, true);505}506}507}508509// Only updates the linked frames of the given node, not the node itself (in case it's a frame node).510void VisualShaderGraphPlugin::update_frames(VisualShader::Type p_type, int p_node) {511GraphEdit *graph = editor->graph;512if (!graph) {513return;514}515516Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_node);517if (vsnode.is_null()) {518WARN_PRINT("Update linked frames: Node not found.");519return;520}521522int frame_vsnode_id = vsnode->get_frame();523if (frame_vsnode_id == -1) {524return;525}526527Ref<VisualShaderNodeFrame> frame_node = visual_shader->get_node(p_type, frame_vsnode_id);528if (frame_node.is_null() || !links.has(frame_vsnode_id)) {529return;530}531532GraphFrame *frame = Object::cast_to<GraphFrame>(links[frame_vsnode_id].graph_element);533if (!frame) {534return;535}536537// Update the frame node recursively.538editor->graph->_update_graph_frame(frame);539}540541void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) {542if (editor->get_current_shader_type() == p_type && links.has(p_id)) {543links[p_id].graph_element->set_position_offset(p_position * editor->cached_theme_base_scale);544}545}546547bool VisualShaderGraphPlugin::is_preview_visible(int p_id) const {548return links[p_id].preview_visible;549}550551void VisualShaderGraphPlugin::clear_links() {552links.clear();553}554555void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphElement *p_graph_element) {556links.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 } });557}558559void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, VisualShaderNode::PortType p_port_type, TextureButton *p_button) {560links[p_node_id].output_ports.insert(p_port, { p_port_type, p_button });561}562563void VisualShaderGraphPlugin::register_parameter_name(int p_node_id, LineEdit *p_parameter_name) {564links[p_node_id].parameter_name = p_parameter_name;565}566567void VisualShaderGraphPlugin::update_theme() {568vector_expanded_color[0] = editor->get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)); // red569vector_expanded_color[1] = editor->get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)); // green570vector_expanded_color[2] = editor->get_theme_color(SNAME("axis_z_color"), EditorStringName(Editor)); // blue571vector_expanded_color[3] = editor->get_theme_color(SNAME("axis_w_color"), EditorStringName(Editor)); // alpha572573Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", EditorStringName(EditorFonts));574Ref<Font> label_bold_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_bold_msdf", EditorStringName(EditorFonts));575vs_msdf_fonts_theme->set_font(SceneStringName(font), "Label", label_font);576vs_msdf_fonts_theme->set_font(SceneStringName(font), "GraphNodeTitleLabel", label_bold_font);577if (!EditorThemeManager::is_dark_icon_and_font()) {578// Override the color to white for light themes.579vs_msdf_fonts_theme->set_color(SceneStringName(font_color), "GraphNodeTitleLabel", Color(1, 1, 1));580}581vs_msdf_fonts_theme->set_font(SceneStringName(font), "LineEdit", label_font);582vs_msdf_fonts_theme->set_font(SceneStringName(font), "Button", label_font);583}584585bool VisualShaderGraphPlugin::is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const {586bool result = false;587588Ref<VisualShaderNodeParameter> parameter_node = Object::cast_to<VisualShaderNodeParameter>(visual_shader->get_node_unchecked(p_type, p_node).ptr());589if (parameter_node.is_valid()) {590if (parameter_node->get_qualifier() == VisualShaderNodeParameter::QUAL_INSTANCE) {591return true;592}593}594595const LocalVector<int> &prev_connected_nodes = visual_shader->get_prev_connected_nodes(p_type, p_node);596597for (const int &E : prev_connected_nodes) {598result = is_node_has_parameter_instances_relatively(p_type, E);599if (result) {600break;601}602}603604return result;605}606607void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool p_just_update, bool p_update_frames) {608if (visual_shader.is_null() || p_type != editor->get_current_shader_type()) {609return;610}611GraphEdit *graph = editor->graph;612if (!graph) {613return;614}615VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();616if (!graph_plugin) {617return;618}619Shader::Mode mode = visual_shader->get_mode();620621Control *offset;622623const Color type_color[] = {624EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"),625EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"),626EDITOR_GET("editors/visual_editors/connection_colors/scalar_color"),627EDITOR_GET("editors/visual_editors/connection_colors/vector2_color"),628EDITOR_GET("editors/visual_editors/connection_colors/vector3_color"),629EDITOR_GET("editors/visual_editors/connection_colors/vector4_color"),630EDITOR_GET("editors/visual_editors/connection_colors/boolean_color"),631EDITOR_GET("editors/visual_editors/connection_colors/transform_color"),632EDITOR_GET("editors/visual_editors/connection_colors/sampler_color"),633};634635// Keep in sync with VisualShaderNode::Category.636const Color category_color[VisualShaderNode::Category::CATEGORY_MAX] = {637Color(0.0, 0.0, 0.0), // None (default, not used)638EDITOR_GET("editors/visual_editors/category_colors/output_color"),639EDITOR_GET("editors/visual_editors/category_colors/color_color"),640EDITOR_GET("editors/visual_editors/category_colors/conditional_color"),641EDITOR_GET("editors/visual_editors/category_colors/input_color"),642EDITOR_GET("editors/visual_editors/category_colors/scalar_color"),643EDITOR_GET("editors/visual_editors/category_colors/textures_color"),644EDITOR_GET("editors/visual_editors/category_colors/transform_color"),645EDITOR_GET("editors/visual_editors/category_colors/utility_color"),646EDITOR_GET("editors/visual_editors/category_colors/vector_color"),647EDITOR_GET("editors/visual_editors/category_colors/special_color"),648EDITOR_GET("editors/visual_editors/category_colors/particle_color"),649};650651static const String vector_expanded_name[4] = { "red", "green", "blue", "alpha" };652653Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);654ERR_FAIL_COND(vsnode.is_null());655656Ref<VisualShaderNodeResizableBase> resizable_node = vsnode;657bool is_resizable = resizable_node.is_valid();658Size2 size = Size2(0, 0);659660Ref<VisualShaderNodeGroupBase> group_node = vsnode;661bool is_group = group_node.is_valid();662663Ref<VisualShaderNodeFrame> frame_node = vsnode;664bool is_frame = frame_node.is_valid();665666Ref<VisualShaderNodeExpression> expression_node = group_node;667bool is_expression = expression_node.is_valid();668String expression = "";669670Ref<VisualShaderNodeReroute> reroute_node = vsnode;671bool is_reroute = reroute_node.is_valid();672673Ref<VisualShaderNodeCustom> custom_node = vsnode;674if (custom_node.is_valid()) {675custom_node->_set_initialized(true);676}677678GraphElement *node;679if (is_frame) {680GraphFrame *frame = memnew(GraphFrame);681frame->set_title(vsnode->get_caption());682node = frame;683} else if (is_reroute) {684VSRerouteNode *reroute_gnode = memnew(VSRerouteNode);685reroute_gnode->set_ignore_invalid_connection_type(true);686node = reroute_gnode;687} else {688VSGraphNode *gnode = memnew(VSGraphNode);689gnode->set_title(vsnode->get_caption());690node = gnode;691}692node->set_name(itos(p_id));693694// All nodes are closable except the output node.695if (p_id >= 2) {696vsnode->set_deletable(true);697node->connect("delete_request", callable_mp(editor, &VisualShaderEditor::_delete_node_request).bind(p_type, p_id), CONNECT_DEFERRED);698}699graph->add_child(node);700node->set_theme(vs_msdf_fonts_theme);701702// Set the node's titlebar color based on its category.703if (vsnode->get_category() != VisualShaderNode::CATEGORY_NONE && !is_frame && !is_reroute) {704Ref<StyleBoxFlat> sb_colored = editor->get_theme_stylebox("titlebar", "GraphNode")->duplicate();705sb_colored->set_bg_color(category_color[vsnode->get_category()]);706node->add_theme_style_override("titlebar", sb_colored);707708Ref<StyleBoxFlat> sb_colored_selected = editor->get_theme_stylebox("titlebar_selected", "GraphNode")->duplicate();709sb_colored_selected->set_bg_color(category_color[vsnode->get_category()].lightened(0.2));710node->add_theme_style_override("titlebar_selected", sb_colored_selected);711}712713if (p_just_update) {714Link &link = links[p_id];715716link.visual_node = vsnode.ptr();717link.graph_element = node;718link.preview_box = nullptr;719link.preview_pos = -1;720link.output_ports.clear();721link.input_ports.clear();722} else {723register_link(p_type, p_id, vsnode.ptr(), node);724}725726if (is_resizable) {727size = resizable_node->get_size();728729node->set_resizable(true);730node->connect("resize_end", callable_mp(editor, &VisualShaderEditor::_node_resized).bind((int)p_type, p_id));731node->set_size(size);732// node->call_deferred(SNAME("set_size"), size);733// editor->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size);734}735736if (is_expression) {737expression = expression_node->get_expression();738}739740node->set_position_offset(visual_shader->get_node_position(p_type, p_id) * editor->cached_theme_base_scale);741742node->connect("dragged", callable_mp(editor, &VisualShaderEditor::_node_dragged).bind(p_id));743744Control *custom_editor = nullptr;745int port_offset = 1;746747if (p_update_frames) {748if (vsnode->get_frame() > -1) {749graph->attach_graph_element_to_frame(itos(p_id), itos(vsnode->get_frame()));750} else {751graph->detach_graph_element_from_frame(itos(p_id));752}753}754755if (is_frame) {756GraphFrame *graph_frame = Object::cast_to<GraphFrame>(node);757ERR_FAIL_NULL(graph_frame);758759graph_frame->set_tint_color_enabled(frame_node->is_tint_color_enabled());760graph_frame->set_tint_color(frame_node->get_tint_color());761762// Add hint label.763Label *frame_hint_label = memnew(Label);764frame_hint_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);765node->add_child(frame_hint_label);766frame_hint_label->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);767frame_hint_label->set_vertical_alignment(VerticalAlignment::VERTICAL_ALIGNMENT_CENTER);768frame_hint_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);769frame_hint_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);770frame_hint_label->set_text(TTR("Drag and drop nodes here to attach them."));771frame_hint_label->set_modulate(Color(1.0, 1.0, 1.0, 0.3));772graph_frame->set_autoshrink_enabled(frame_node->is_autoshrink_enabled());773774if (frame_node->get_attached_nodes().is_empty()) {775frame_hint_label->show();776} else {777frame_hint_label->hide();778}779780// Attach all nodes.781if (p_update_frames && frame_node->get_attached_nodes().size() > 0) {782for (const int &id : frame_node->get_attached_nodes()) {783graph->attach_graph_element_to_frame(itos(id), node->get_name());784}785}786787// We should be done here.788return;789}790791if (!is_reroute) {792Control *content_offset = memnew(Control);793content_offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));794node->add_child(content_offset);795}796797if (is_group) {798port_offset += 1;799}800801// Set the minimum width of a node based on the preview size to avoid a resize when toggling the preview.802Ref<StyleBoxFlat> graph_node_stylebox = graph->get_theme_stylebox(SceneStringName(panel), "GraphNode");803int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size");804if (!is_frame && !is_reroute) {805node->set_custom_minimum_size(Size2((Math::ceil(graph_node_stylebox->get_minimum_size().width) + port_preview_size) * EDSCALE, 0));806}807808Ref<VisualShaderNodeParticleEmit> emit = vsnode;809if (emit.is_valid()) {810node->set_custom_minimum_size(Size2(200 * EDSCALE, 0));811}812813Ref<VisualShaderNodeParameterRef> parameter_ref = vsnode;814if (parameter_ref.is_valid()) {815parameter_ref->set_shader_rid(visual_shader->get_rid());816parameter_ref->update_parameter_type();817}818819Ref<VisualShaderNodeVarying> varying = vsnode;820if (varying.is_valid()) {821varying->set_shader_rid(visual_shader->get_rid());822}823824Ref<VisualShaderNodeParameter> parameter = vsnode;825HBoxContainer *hb = nullptr;826827if (parameter.is_valid()) {828LineEdit *parameter_name = memnew(LineEdit);829register_parameter_name(p_id, parameter_name);830parameter_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);831parameter_name->set_text(parameter->get_parameter_name());832parameter_name->connect(SceneStringName(text_submitted), callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_changed).bind(p_id));833parameter_name->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_focus_out).bind(parameter_name, p_id));834835if (vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {836hb = memnew(HBoxContainer);837hb->add_child(parameter_name);838node->add_child(hb);839} else {840node->add_child(parameter_name);841}842port_offset++;843}844845for (int i = 0; i < editor->plugins.size(); i++) {846vsnode->set_meta("id", p_id);847vsnode->set_meta("shader_type", (int)p_type);848custom_editor = editor->plugins.write[i]->create_editor(visual_shader, vsnode);849vsnode->remove_meta("id");850vsnode->remove_meta("shader_type");851if (custom_editor) {852if (vsnode->is_show_prop_names()) {853custom_editor->call_deferred(SNAME("_show_prop_names"), true);854}855break;856}857}858859if (custom_node.is_valid()) {860bool first = true;861VBoxContainer *vbox = nullptr;862863int i = 0;864for (List<VisualShaderNodeCustom::DropDownListProperty>::ConstIterator itr = custom_node->dp_props.begin(); itr != custom_node->dp_props.end(); ++itr, ++i) {865const VisualShaderNodeCustom::DropDownListProperty &dp = *itr;866867if (first) {868first = false;869vbox = memnew(VBoxContainer);870node->add_child(vbox);871port_offset++;872}873874HBoxContainer *hbox = memnew(HBoxContainer);875vbox->add_child(hbox);876hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);877878String prop_name = dp.name.strip_edges();879if (!prop_name.is_empty()) {880Label *label = memnew(Label);881label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);882label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.883label->set_text(prop_name + ":");884hbox->add_child(label);885}886887OptionButton *op = memnew(OptionButton);888hbox->add_child(op);889op->set_h_size_flags(Control::SIZE_EXPAND_FILL);890op->connect(SceneStringName(item_selected), callable_mp(editor, &VisualShaderEditor::_set_custom_node_option).bind(p_id, i), CONNECT_DEFERRED);891892for (const String &s : dp.options) {893op->add_item(s);894}895if (custom_node->dp_selected_cache.has(i)) {896op->select(custom_node->dp_selected_cache[i]);897} else {898op->select(0);899}900}901}902903Ref<VisualShaderNodeCurveTexture> curve = vsnode;904Ref<VisualShaderNodeCurveXYZTexture> curve_xyz = vsnode;905906bool is_curve = curve.is_valid() || curve_xyz.is_valid();907if (is_curve) {908hb = memnew(HBoxContainer);909node->add_child(hb);910}911912if (curve.is_valid()) {913custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);914915if (curve->get_texture().is_valid()) {916curve->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve).bind(p_id));917}918919CurveEditor *curve_editor = memnew(CurveEditor);920node->add_child(curve_editor);921register_curve_editor(p_id, 0, curve_editor);922curve_editor->set_custom_minimum_size(Size2(300, 0));923curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);924if (curve->get_texture().is_valid()) {925curve_editor->set_curve(curve->get_texture()->get_curve());926}927}928929if (curve_xyz.is_valid()) {930custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);931932if (curve_xyz->get_texture().is_valid()) {933curve_xyz->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve_xyz).bind(p_id));934}935936CurveEditor *curve_editor_x = memnew(CurveEditor);937node->add_child(curve_editor_x);938register_curve_editor(p_id, 0, curve_editor_x);939curve_editor_x->set_custom_minimum_size(Size2(300, 0));940curve_editor_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);941if (curve_xyz->get_texture().is_valid()) {942curve_editor_x->set_curve(curve_xyz->get_texture()->get_curve_x());943}944945CurveEditor *curve_editor_y = memnew(CurveEditor);946node->add_child(curve_editor_y);947register_curve_editor(p_id, 1, curve_editor_y);948curve_editor_y->set_custom_minimum_size(Size2(300, 0));949curve_editor_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);950if (curve_xyz->get_texture().is_valid()) {951curve_editor_y->set_curve(curve_xyz->get_texture()->get_curve_y());952}953954CurveEditor *curve_editor_z = memnew(CurveEditor);955node->add_child(curve_editor_z);956register_curve_editor(p_id, 2, curve_editor_z);957curve_editor_z->set_custom_minimum_size(Size2(300, 0));958curve_editor_z->set_h_size_flags(Control::SIZE_EXPAND_FILL);959if (curve_xyz->get_texture().is_valid()) {960curve_editor_z->set_curve(curve_xyz->get_texture()->get_curve_z());961}962}963964if (custom_editor) {965if (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) == ""))) {966// Will be embedded in first port.967} else {968port_offset++;969node->add_child(custom_editor);970custom_editor = nullptr;971}972}973974if (is_group) {975if (group_node->is_editable()) {976HBoxContainer *hb2 = memnew(HBoxContainer);977978String input_port_name = "input" + itos(group_node->get_free_input_port_id());979String output_port_name = "output" + itos(group_node->get_free_output_port_id());980981for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) {982if (i < vsnode->get_input_port_count()) {983if (input_port_name == vsnode->get_input_port_name(i)) {984input_port_name = "_" + input_port_name;985}986}987if (i < vsnode->get_output_port_count()) {988if (output_port_name == vsnode->get_output_port_name(i)) {989output_port_name = "_" + output_port_name;990}991}992}993994Button *add_input_btn = memnew(Button);995add_input_btn->set_text(TTR("Add Input"));996add_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);997hb2->add_child(add_input_btn);998999hb2->add_spacer();10001001Button *add_output_btn = memnew(Button);1002add_output_btn->set_text(TTR("Add Output"));1003add_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);1004hb2->add_child(add_output_btn);10051006node->add_child(hb2);1007}1008}10091010int output_port_count = 0;1011for (int i = 0; i < vsnode->get_output_port_count(); i++) {1012if (vsnode->_is_output_port_expanded(i)) {1013switch (vsnode->get_output_port_type(i)) {1014case VisualShaderNode::PORT_TYPE_VECTOR_2D: {1015output_port_count += 2;1016} break;1017case VisualShaderNode::PORT_TYPE_VECTOR_3D: {1018output_port_count += 3;1019} break;1020case VisualShaderNode::PORT_TYPE_VECTOR_4D: {1021output_port_count += 4;1022} break;1023default:1024break;1025}1026}1027output_port_count++;1028}1029int max_ports = MAX(vsnode->get_input_port_count(), output_port_count);1030VisualShaderNode::PortType expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1031int expanded_port_counter = 0;10321033for (int i = 0, j = 0; i < max_ports; i++, j++) {1034switch (expanded_type) {1035case VisualShaderNode::PORT_TYPE_VECTOR_2D: {1036if (expanded_port_counter >= 2) {1037expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1038expanded_port_counter = 0;1039i -= 2;1040}1041} break;1042case VisualShaderNode::PORT_TYPE_VECTOR_3D: {1043if (expanded_port_counter >= 3) {1044expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1045expanded_port_counter = 0;1046i -= 3;1047}1048} break;1049case VisualShaderNode::PORT_TYPE_VECTOR_4D: {1050if (expanded_port_counter >= 4) {1051expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;1052expanded_port_counter = 0;1053i -= 4;1054}1055} break;1056default:1057break;1058}10591060if (vsnode->is_port_separator(i)) {1061HSeparator *separator = memnew(HSeparator);1062separator->add_theme_style_override("separator", editor->get_theme_stylebox("separator", "GraphNode"));1063node->add_child(separator);1064port_offset++;1065}10661067bool valid_left = j < vsnode->get_input_port_count();1068VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR;1069bool port_left_used = false;1070String name_left;1071if (valid_left) {1072name_left = vsnode->get_input_port_name(j);1073port_left = vsnode->get_input_port_type(j);1074for (const VisualShader::Connection &E : connections) {1075if (E.to_node == p_id && E.to_port == j) {1076port_left_used = true;1077break;1078}1079}1080}10811082bool valid_right = true;1083VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR;1084String name_right;10851086if (expanded_type == VisualShaderNode::PORT_TYPE_SCALAR) {1087valid_right = i < vsnode->get_output_port_count();1088if (valid_right) {1089name_right = vsnode->get_output_port_name(i);1090port_right = vsnode->get_output_port_type(i);1091}1092} else {1093name_right = vector_expanded_name[expanded_port_counter++];1094}10951096bool is_first_hbox = false;1097if (i == 0 && hb != nullptr) {1098is_first_hbox = true;1099} else {1100hb = memnew(HBoxContainer);1101}1102hb->add_theme_constant_override("separation", 7 * EDSCALE);11031104// Default value button/property editor.1105Variant default_value;11061107if (valid_left && !port_left_used) {1108default_value = vsnode->get_input_port_default_value(j);1109}11101111Button *default_input_btn = memnew(Button);1112hb->add_child(default_input_btn);1113register_default_input_button(p_id, j, default_input_btn);1114default_input_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_edit_port_default_input).bind(default_input_btn, p_id, j));1115if (default_value.get_type() != Variant::NIL) { // only a label1116set_input_port_default_value(p_type, p_id, j, default_value);1117} else {1118default_input_btn->hide();1119}11201121if (j == 0 && custom_editor) {1122hb->add_child(custom_editor);1123custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);1124} else {1125if (valid_left) {1126if (is_group) {1127OptionButton *type_box = memnew(OptionButton);1128hb->add_child(type_box);1129type_box->add_item(TTR("Float"));1130type_box->add_item(TTR("Int"));1131type_box->add_item(TTR("UInt"));1132type_box->add_item(TTR("Vector2"));1133type_box->add_item(TTR("Vector3"));1134type_box->add_item(TTR("Vector4"));1135type_box->add_item(TTR("Boolean"));1136type_box->add_item(TTR("Transform"));1137type_box->add_item(TTR("Sampler"));1138type_box->select(group_node->get_input_port_type(j));1139type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));1140type_box->connect(SceneStringName(item_selected), callable_mp(editor, &VisualShaderEditor::_change_input_port_type).bind(p_id, j), CONNECT_DEFERRED);11411142LineEdit *name_box = memnew(LineEdit);1143hb->add_child(name_box);1144name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));1145name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);1146name_box->set_text(name_left);1147name_box->connect(SceneStringName(text_submitted), callable_mp(editor, &VisualShaderEditor::_change_input_port_name).bind(name_box, p_id, j), CONNECT_DEFERRED);1148name_box->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, j, false), CONNECT_DEFERRED);11491150Button *remove_btn = memnew(Button);1151remove_btn->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));1152remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);1153remove_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, j), CONNECT_DEFERRED);1154hb->add_child(remove_btn);1155} else {1156Label *label = memnew(Label);1157label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1158label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.1159label->set_text(name_left);1160label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor")));1161hb->add_child(label);11621163if (vsnode->is_input_port_default(j, mode) && !port_left_used) {1164Label *hint_label = memnew(Label);1165hint_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1166hint_label->set_text(TTR("[default]"));1167hint_label->add_theme_color_override(SceneStringName(font_color), editor->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit")));1168hint_label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor")));1169hb->add_child(hint_label);1170}1171}1172}11731174if (!is_group && !is_first_hbox) {1175hb->add_spacer();1176}11771178if (valid_right) {1179if (is_group) {1180Button *remove_btn = memnew(Button);1181remove_btn->set_button_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));1182remove_btn->set_tooltip_text(TTR("Remove") + " " + name_right);1183remove_btn->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED);1184hb->add_child(remove_btn);11851186LineEdit *name_box = memnew(LineEdit);1187hb->add_child(name_box);1188name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));1189name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);1190name_box->set_text(name_right);1191name_box->connect(SceneStringName(text_submitted), callable_mp(editor, &VisualShaderEditor::_change_output_port_name).bind(name_box, p_id, i), CONNECT_DEFERRED);1192name_box->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, i, true), CONNECT_DEFERRED);11931194OptionButton *type_box = memnew(OptionButton);1195hb->add_child(type_box);1196type_box->add_item(TTR("Float"));1197type_box->add_item(TTR("Int"));1198type_box->add_item(TTR("UInt"));1199type_box->add_item(TTR("Vector2"));1200type_box->add_item(TTR("Vector3"));1201type_box->add_item(TTR("Vector4"));1202type_box->add_item(TTR("Boolean"));1203type_box->add_item(TTR("Transform"));1204type_box->select(group_node->get_output_port_type(i));1205type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));1206type_box->connect(SceneStringName(item_selected), callable_mp(editor, &VisualShaderEditor::_change_output_port_type).bind(p_id, i), CONNECT_DEFERRED);1207} else {1208Label *label = memnew(Label);1209label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1210label->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.1211label->set_text(name_right);1212label->add_theme_style_override(CoreStringName(normal), editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact1213hb->add_child(label);1214}1215}1216}12171218if (valid_right) {1219if (expanded_port_counter == 0 && vsnode->is_output_port_expandable(i)) {1220TextureButton *expand = memnew(TextureButton);1221expand->set_accessibility_name(TTRC("Expand output port"));1222expand->set_toggle_mode(true);1223expand->set_texture_normal(editor->get_editor_theme_icon(SNAME("GuiTreeArrowRight")));1224expand->set_texture_pressed(editor->get_editor_theme_icon(SNAME("GuiTreeArrowDown")));1225expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER);1226expand->set_pressed(vsnode->_is_output_port_expanded(i));1227expand->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_expand_output_port).bind(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED);1228hb->add_child(expand);1229}1230if (vsnode->has_output_port_preview(i) && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) {1231TextureButton *preview = memnew(TextureButton);1232preview->set_accessibility_name(TTRC("Select preview port"));1233preview->set_toggle_mode(true);1234preview->set_texture_normal(editor->get_editor_theme_icon(SNAME("GuiVisibilityHidden")));1235preview->set_texture_pressed(editor->get_editor_theme_icon(SNAME("GuiVisibilityVisible")));1236preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);12371238register_output_port(p_id, j, port_right, preview);12391240preview->connect(SceneStringName(pressed), callable_mp(editor, &VisualShaderEditor::_preview_select_port).bind(p_id, j), CONNECT_DEFERRED);1241hb->add_child(preview);1242}1243}12441245if (is_group) {1246offset = memnew(Control);1247offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));1248node->add_child(offset);1249port_offset++;1250}12511252if (!is_first_hbox && !is_reroute) {1253node->add_child(hb);1254if (curve_xyz.is_valid()) {1255node->move_child(hb, 1 + expanded_port_counter);1256}1257}12581259if (expanded_type != VisualShaderNode::PORT_TYPE_SCALAR) {1260continue;1261}12621263int idx = is_first_hbox ? 1 : i + port_offset;1264if (is_reroute) {1265idx = 0;1266}1267if (!is_frame) {1268GraphNode *graph_node = Object::cast_to<GraphNode>(node);12691270graph_node->set_slot(idx, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]);12711272if (vsnode->_is_output_port_expanded(i)) {1273switch (vsnode->get_output_port_type(i)) {1274case VisualShaderNode::PORT_TYPE_VECTOR_2D: {1275port_offset++;1276valid_left = (i + 1) < vsnode->get_input_port_count();1277port_left = VisualShaderNode::PORT_TYPE_SCALAR;1278if (valid_left) {1279port_left = vsnode->get_input_port_type(i + 1);1280}1281graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);1282port_offset++;12831284valid_left = (i + 2) < vsnode->get_input_port_count();1285port_left = VisualShaderNode::PORT_TYPE_SCALAR;1286if (valid_left) {1287port_left = vsnode->get_input_port_type(i + 2);1288}1289graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);12901291expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_2D;1292} break;1293case VisualShaderNode::PORT_TYPE_VECTOR_3D: {1294port_offset++;1295valid_left = (i + 1) < vsnode->get_input_port_count();1296port_left = VisualShaderNode::PORT_TYPE_SCALAR;1297if (valid_left) {1298port_left = vsnode->get_input_port_type(i + 1);1299}1300graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);1301port_offset++;13021303valid_left = (i + 2) < vsnode->get_input_port_count();1304port_left = VisualShaderNode::PORT_TYPE_SCALAR;1305if (valid_left) {1306port_left = vsnode->get_input_port_type(i + 2);1307}1308graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);1309port_offset++;13101311valid_left = (i + 3) < vsnode->get_input_port_count();1312port_left = VisualShaderNode::PORT_TYPE_SCALAR;1313if (valid_left) {1314port_left = vsnode->get_input_port_type(i + 3);1315}1316graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);13171318expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_3D;1319} break;1320case VisualShaderNode::PORT_TYPE_VECTOR_4D: {1321port_offset++;1322valid_left = (i + 1) < vsnode->get_input_port_count();1323port_left = VisualShaderNode::PORT_TYPE_SCALAR;1324if (valid_left) {1325port_left = vsnode->get_input_port_type(i + 1);1326}1327graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);1328port_offset++;13291330valid_left = (i + 2) < vsnode->get_input_port_count();1331port_left = VisualShaderNode::PORT_TYPE_SCALAR;1332if (valid_left) {1333port_left = vsnode->get_input_port_type(i + 2);1334}1335graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);1336port_offset++;13371338valid_left = (i + 3) < vsnode->get_input_port_count();1339port_left = VisualShaderNode::PORT_TYPE_SCALAR;1340if (valid_left) {1341port_left = vsnode->get_input_port_type(i + 3);1342}1343graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);1344port_offset++;13451346valid_left = (i + 4) < vsnode->get_input_port_count();1347port_left = VisualShaderNode::PORT_TYPE_SCALAR;1348if (valid_left) {1349port_left = vsnode->get_input_port_type(i + 4);1350}1351graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[3]);13521353expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_4D;1354} break;1355default:1356break;1357}1358}1359}1360}13611362bool has_relative_parameter_instances = false;1363if (vsnode->get_output_port_for_preview() >= 0) {1364has_relative_parameter_instances = is_node_has_parameter_instances_relatively(p_type, p_id);1365show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview(), !has_relative_parameter_instances);1366} else if (!is_reroute) {1367offset = memnew(Control);1368offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));1369node->add_child(offset);1370}13711372String error = vsnode->get_warning(mode, p_type);1373if (has_relative_parameter_instances) {1374error += "\n" + TTR("The 2D preview cannot correctly show the result retrieved from instance parameter.");1375}1376if (!error.is_empty()) {1377Label *error_label = memnew(Label);1378error_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);1379error_label->add_theme_color_override(SceneStringName(font_color), editor->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));1380error_label->set_text(error);1381error_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);1382node->add_child(error_label);1383}13841385if (is_expression) {1386CodeEdit *expression_box = memnew(CodeEdit);1387Ref<CodeHighlighter> expression_syntax_highlighter;1388expression_syntax_highlighter.instantiate();1389expression_node->set_ctrl_pressed(expression_box, 0);1390expression_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);1391node->add_child(expression_box);13921393Control *offset2 = memnew(Control);1394offset2->set_custom_minimum_size(Vector2(0, 11 * EDSCALE));1395node->add_child(offset2);13961397register_expression_edit(p_id, expression_box);13981399Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");1400Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");1401Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");1402Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");1403Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");1404Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");1405Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");1406Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");14071408expression_box->set_syntax_highlighter(expression_syntax_highlighter);14091410for (const String &E : editor->keyword_list) {1411if (ShaderLanguage::is_control_flow_keyword(E)) {1412expression_syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);1413} else {1414expression_syntax_highlighter->add_keyword_color(E, keyword_color);1415}1416}14171418expression_box->begin_bulk_theme_override();1419expression_box->add_theme_font_override(SceneStringName(font), editor->get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)));1420expression_box->add_theme_font_size_override(SceneStringName(font_size), editor->get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts)));1421expression_box->add_theme_color_override(SceneStringName(font_color), text_color);1422expression_box->end_bulk_theme_override();14231424expression_syntax_highlighter->set_number_color(number_color);1425expression_syntax_highlighter->set_symbol_color(symbol_color);1426expression_syntax_highlighter->set_function_color(function_color);1427expression_syntax_highlighter->set_member_variable_color(members_color);1428expression_syntax_highlighter->add_color_region("/*", "*/", comment_color, false);1429expression_syntax_highlighter->add_color_region("//", "", comment_color, true);14301431expression_box->clear_comment_delimiters();1432expression_box->add_comment_delimiter("/*", "*/", false);1433expression_box->add_comment_delimiter("//", "", true);14341435if (!expression_box->has_auto_brace_completion_open_key("/*")) {1436expression_box->add_auto_brace_completion_pair("/*", "*/");1437}14381439expression_box->set_text(expression);1440expression_box->set_context_menu_enabled(false);1441expression_box->set_draw_line_numbers(true);14421443expression_box->connect(SceneStringName(focus_exited), callable_mp(editor, &VisualShaderEditor::_expression_focus_out).bind(expression_box, p_id));1444}1445}14461447void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id, bool p_just_update) {1448if (editor->get_current_shader_type() == p_type && links.has(p_id)) {1449GraphEdit *graph_edit = editor->graph;1450if (!graph_edit) {1451return;1452}14531454graph_edit->remove_child(links[p_id].graph_element);1455memdelete(links[p_id].graph_element);1456if (!p_just_update) {1457links.erase(p_id);1458}1459}1460}14611462void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {1463GraphEdit *graph = editor->graph;1464if (!graph) {1465return;1466}14671468if (visual_shader.is_valid() && editor->get_current_shader_type() == p_type) {1469// Update reroute nodes since their port type might have changed.1470Ref<VisualShaderNodeReroute> reroute_to = visual_shader->get_node(p_type, p_to_node);1471Ref<VisualShaderNodeReroute> reroute_from = visual_shader->get_node(p_type, p_from_node);1472if (reroute_to.is_valid() || reroute_from.is_valid()) {1473update_reroute_nodes();1474}14751476graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);14771478connections.push_back({ p_from_node, p_from_port, p_to_node, p_to_port });1479if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr) {1480links[p_to_node].input_ports[p_to_port].default_input_button->hide();1481}1482}1483}14841485void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {1486GraphEdit *graph = editor->graph;1487if (!graph) {1488return;1489}14901491if (visual_shader.is_valid() && editor->get_current_shader_type() == p_type) {1492graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);14931494for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {1495if (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) {1496connections.erase(E);1497break;1498}1499}1500if (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) {1501links[p_to_node].input_ports[p_to_port].default_input_button->show();1502set_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));1503}1504}1505}15061507/////////////////15081509void VisualShaderEditedProperty::_bind_methods() {1510ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualShaderEditedProperty::set_edited_property);1511ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualShaderEditedProperty::get_edited_property);15121513ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property");1514}15151516void VisualShaderEditedProperty::set_edited_property(const Variant &p_variant) {1517edited_property = p_variant;1518}15191520Variant VisualShaderEditedProperty::get_edited_property() const {1521return edited_property;1522}15231524/////////////////15251526Vector2 VisualShaderEditor::selection_center;1527List<VisualShaderEditor::CopyItem> VisualShaderEditor::copy_items_buffer;1528List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer;15291530void VisualShaderEditor::edit_shader(const Ref<Shader> &p_shader) {1531shader_fully_loaded = false;1532bool changed = false;1533VisualShader *visual_shader_ptr = Object::cast_to<VisualShader>(p_shader.ptr());1534if (visual_shader_ptr) {1535if (visual_shader.is_null()) {1536changed = true;1537} else {1538if (visual_shader.ptr() != visual_shader_ptr) {1539changed = true;1540}1541}1542visual_shader = p_shader;1543graph_plugin->register_shader(visual_shader.ptr());15441545visual_shader->connect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));1546_set_mode(visual_shader->get_mode());15471548preview_material->set_shader(visual_shader);1549_update_nodes();1550} else {1551if (visual_shader.is_valid()) {1552visual_shader->disconnect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));1553}1554visual_shader.unref();1555}15561557if (visual_shader.is_null()) {1558hide();1559} else {1560if (changed) { // to avoid tree collapse1561_update_varying_tree();1562_update_options_menu();1563_update_preview();1564_update_graph();1565callable_mp(this, &VisualShaderEditor::_restore_editor_state).call_deferred();1566}1567}1568}15691570void VisualShaderEditor::use_menu_bar(MenuButton *p_file_menu) {1571p_file_menu->set_switch_on_hover(false);1572toolbar_hflow->add_child(p_file_menu);1573toolbar_hflow->move_child(p_file_menu, 2); // Toggle Files Panel button + separator.1574}15751576void VisualShaderEditor::apply_shaders() {1577// Stub. TODO: Implement apply_shaders in visual shaders for parity with text shaders.1578}15791580bool VisualShaderEditor::is_unsaved() const {1581// Stub. TODO: Implement is_unsaved in visual shaders for parity with text shaders.1582return false;1583}15841585void VisualShaderEditor::save_external_data(const String &p_str) {1586ResourceSaver::save(visual_shader, visual_shader->get_path());1587}15881589void VisualShaderEditor::validate_script() {1590if (visual_shader.is_valid()) {1591_update_nodes();1592}1593}15941595void VisualShaderEditor::save_editor_layout() {1596const String id_string = _get_cache_id_string();15971598const String offset_cache_key = _get_cache_key("offset");1599const String zoom_cache_key = _get_cache_key("zoom");1600vs_editor_cache->set_value(id_string, offset_cache_key, graph->get_scroll_offset() / EDSCALE);1601vs_editor_cache->set_value(id_string, zoom_cache_key, graph->get_zoom());1602vs_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));1603}16041605void VisualShaderEditor::set_current_shader_type(VisualShader::Type p_type) {1606current_type = p_type;16071608const String id_string = _get_cache_id_string();16091610vs_editor_cache->set_value(id_string, "edited_type", p_type);1611vs_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));16121613const String offset_cache_key = _get_cache_key("offset");1614const String zoom_cache_key = _get_cache_key("zoom");1615const Vector2 saved_scroll_offset = vs_editor_cache->get_value(id_string, offset_cache_key, Vector2());1616const real_t saved_zoom = vs_editor_cache->get_value(id_string, zoom_cache_key, 1.0);16171618graph->set_scroll_offset(saved_scroll_offset);1619graph->set_zoom(saved_zoom);1620}16211622VisualShader::Type VisualShaderEditor::get_current_shader_type() const {1623return current_type;1624}16251626void VisualShaderEditor::add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {1627if (plugins.has(p_plugin)) {1628return;1629}1630plugins.push_back(p_plugin);1631}16321633void VisualShaderEditor::remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {1634plugins.erase(p_plugin);1635}16361637void VisualShaderEditor::clear_custom_types() {1638for (int i = 0; i < add_options.size(); i++) {1639if (add_options[i].is_custom) {1640add_options.remove_at(i);1641i--;1642}1643}1644}16451646void 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) {1647ERR_FAIL_COND(!p_name.is_valid_ascii_identifier());1648ERR_FAIL_COND(p_type.is_empty() && p_script.is_null());16491650for (int i = 0; i < add_options.size(); i++) {1651const AddOption &op = add_options[i];16521653if (op.is_custom) {1654if (!p_type.is_empty()) {1655if (op.type == p_type) {1656return;1657}1658} else if (op.script == p_script) {1659return;1660}1661}1662}16631664AddOption ao;1665ao.name = p_name;1666ao.type = p_type;1667ao.script = p_script;1668ao.return_type = p_return_icon_type;1669ao.description = p_description;1670ao.category = p_category;1671ao.highend = p_highend;1672ao.is_custom = true;1673ao.is_native = !p_type.is_empty();16741675bool begin = false;1676String root = p_category.get_slicec('/', 0);16771678for (int i = 0; i < add_options.size(); i++) {1679if (add_options[i].is_custom) {1680if (add_options[i].category == root) {1681if (!begin) {1682begin = true;1683}1684} else {1685if (begin) {1686add_options.insert(i, ao);1687return;1688}1689}1690}1691}1692add_options.push_back(ao);1693}16941695Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) {1696Dictionary dict;1697dict["script"] = p_custom_node->get_script();1698dict["name"] = p_custom_node->_get_name();1699dict["description"] = p_custom_node->_get_description();1700dict["return_icon_type"] = p_custom_node->_get_return_icon_type();1701dict["highend"] = p_custom_node->_is_highend();17021703String category = p_custom_node->_get_category();1704category = category.rstrip("/");1705category = category.lstrip("/");1706category = "Addons/" + category;1707if (p_custom_node->has_method("_get_subcategory")) {1708String subcategory = (String)p_custom_node->call("_get_subcategory");1709if (!subcategory.is_empty()) {1710category += "/" + subcategory;1711}1712}1713dict["category"] = category;17141715return dict;1716}17171718void VisualShaderEditor::_get_current_mode_limits(int &r_begin_type, int &r_end_type) const {1719switch (visual_shader->get_mode()) {1720case Shader::MODE_CANVAS_ITEM:1721case Shader::MODE_SPATIAL: {1722r_begin_type = VisualShader::TYPE_VERTEX;1723r_end_type = VisualShader::TYPE_START;1724} break;1725case Shader::MODE_PARTICLES: {1726r_begin_type = VisualShader::TYPE_START;1727r_end_type = VisualShader::TYPE_SKY;1728} break;1729case Shader::MODE_SKY: {1730r_begin_type = VisualShader::TYPE_SKY;1731r_end_type = VisualShader::TYPE_FOG;1732} break;1733case Shader::MODE_FOG: {1734r_begin_type = VisualShader::TYPE_FOG;1735r_end_type = VisualShader::TYPE_TEXTURE_BLIT;1736} break;1737case Shader::MODE_TEXTURE_BLIT: {1738r_begin_type = VisualShader::TYPE_TEXTURE_BLIT;1739r_end_type = VisualShader::TYPE_MAX;1740} break;1741default: {1742} break;1743}1744}17451746void VisualShaderEditor::_script_created(const Ref<Script> &p_script) {1747if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {1748return;1749}1750Ref<VisualShaderNodeCustom> ref;1751ref.instantiate();1752ref->set_script(p_script);17531754Dictionary dict = get_custom_node_data(ref);1755add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);17561757_update_options_menu();1758}17591760void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) {1761if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {1762return;1763}17641765Ref<VisualShaderNodeCustom> ref;1766ref.instantiate();1767ref->set_script(p_script);1768if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {1769for (int i = 0; i < add_options.size(); i++) {1770if (add_options[i].is_custom && add_options[i].script == p_script) {1771add_options.remove_at(i);1772_update_options_menu();1773// TODO: Make indication for the existed custom nodes with that script on graph to be disabled.1774break;1775}1776}1777return;1778}1779Dictionary dict = get_custom_node_data(ref);17801781bool found_type = false;1782bool need_rebuild = false;17831784for (int i = custom_node_option_idx; i < add_options.size(); i++) {1785if (add_options[i].script == p_script) {1786found_type = true;17871788add_options.write[i].name = dict["name"];1789add_options.write[i].return_type = dict["return_icon_type"];1790add_options.write[i].description = dict["description"];1791add_options.write[i].category = dict["category"];1792add_options.write[i].highend = dict["highend"];17931794int begin_type = 0;1795int end_type = 0;1796_get_current_mode_limits(begin_type, end_type);17971798for (int t = begin_type; t < end_type; t++) {1799VisualShader::Type type = (VisualShader::Type)t;1800Vector<int> nodes = visual_shader->get_node_list(type);18011802List<VisualShader::Connection> node_connections;1803visual_shader->get_node_connections(type, &node_connections);18041805List<VisualShader::Connection> custom_node_input_connections;1806List<VisualShader::Connection> custom_node_output_connections;18071808for (const VisualShader::Connection &E : node_connections) {1809int from = E.from_node;1810int from_port = E.from_port;1811int to = E.to_node;1812int to_port = E.to_port;18131814if (graph_plugin->get_node_script(from) == p_script) {1815custom_node_output_connections.push_back({ from, from_port, to, to_port });1816} else if (graph_plugin->get_node_script(to) == p_script) {1817custom_node_input_connections.push_back({ from, from_port, to, to_port });1818}1819}18201821for (int node_id : nodes) {1822Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);1823if (vsnode.is_null()) {1824continue;1825}1826Ref<VisualShaderNodeCustom> custom_node = vsnode;1827if (custom_node.is_null() || custom_node->get_script() != p_script) {1828continue;1829}1830need_rebuild = true;18311832// Removes invalid connections.1833{1834int prev_input_port_count = custom_node->get_input_port_count();1835int prev_output_port_count = custom_node->get_output_port_count();18361837custom_node->update_ports();18381839int input_port_count = custom_node->get_input_port_count();1840int output_port_count = custom_node->get_output_port_count();18411842if (output_port_count != prev_output_port_count) {1843for (const VisualShader::Connection &E : custom_node_output_connections) {1844int from = E.from_node;1845int from_idx = E.from_port;1846int to = E.to_node;1847int to_idx = E.to_port;18481849if (from_idx >= output_port_count) {1850visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);1851graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);1852}1853}1854}1855if (input_port_count != prev_input_port_count) {1856for (const VisualShader::Connection &E : custom_node_input_connections) {1857int from = E.from_node;1858int from_idx = E.from_port;1859int to = E.to_node;1860int to_idx = E.to_port;18611862if (to_idx >= input_port_count) {1863visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);1864graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);1865}1866}1867}1868}18691870graph_plugin->update_node(type, node_id);1871}1872}1873break;1874}1875}18761877if (!found_type) {1878add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);1879}18801881// To prevent updating options multiple times when multiple scripts are saved.1882if (!_block_update_options_menu) {1883_block_update_options_menu = true;18841885callable_mp(this, &VisualShaderEditor::_update_options_menu_deferred);1886}18871888// To prevent rebuilding the shader multiple times when multiple scripts are saved.1889if (need_rebuild && !_block_rebuild_shader) {1890_block_rebuild_shader = true;18911892callable_mp(this, &VisualShaderEditor::_rebuild_shader_deferred);1893}1894}18951896void VisualShaderEditor::_resource_saved(const Ref<Resource> &p_resource) {1897_update_custom_script(Ref<Script>(p_resource.ptr()));1898}18991900void VisualShaderEditor::_resources_removed() {1901bool has_any_instance = false;19021903for (const Ref<Script> &scr : custom_scripts_to_delete) {1904for (int i = custom_node_option_idx; i < add_options.size(); i++) {1905if (add_options[i].script == scr) {1906add_options.remove_at(i);19071908// Removes all node instances using that script from the graph.1909{1910int begin_type = 0;1911int end_type = 0;1912_get_current_mode_limits(begin_type, end_type);19131914for (int t = begin_type; t < end_type; t++) {1915VisualShader::Type type = (VisualShader::Type)t;19161917List<VisualShader::Connection> node_connections;1918visual_shader->get_node_connections(type, &node_connections);19191920for (const VisualShader::Connection &E : node_connections) {1921int from = E.from_node;1922int from_port = E.from_port;1923int to = E.to_node;1924int to_port = E.to_port;19251926if (graph_plugin->get_node_script(from) == scr || graph_plugin->get_node_script(to) == scr) {1927visual_shader->disconnect_nodes(type, from, from_port, to, to_port);1928graph_plugin->disconnect_nodes(type, from, from_port, to, to_port);1929}1930}19311932Vector<int> nodes = visual_shader->get_node_list(type);1933for (int node_id : nodes) {1934Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);1935if (vsnode.is_null()) {1936continue;1937}1938Ref<VisualShaderNodeCustom> custom_node = vsnode;1939if (custom_node.is_null() || custom_node->get_script() != scr) {1940continue;1941}1942visual_shader->remove_node(type, node_id);1943graph_plugin->remove_node(type, node_id, false);19441945has_any_instance = true;1946}1947}1948}19491950break;1951}1952}1953}1954if (has_any_instance) {1955EditorUndoRedoManager::get_singleton()->clear_history(); // Need to clear undo history, otherwise it may lead to hard-detected errors and crashes (since the script was removed).1956ResourceSaver::save(visual_shader, visual_shader->get_path());1957}1958_update_options_menu();19591960custom_scripts_to_delete.clear();1961pending_custom_scripts_to_delete = false;1962}19631964void VisualShaderEditor::_resource_removed(const Ref<Resource> &p_resource) {1965Ref<Script> scr = Ref<Script>(p_resource.ptr());1966if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") {1967return;1968}19691970custom_scripts_to_delete.push_back(scr);19711972if (!pending_custom_scripts_to_delete) {1973pending_custom_scripts_to_delete = true;1974callable_mp(this, &VisualShaderEditor::_resources_removed).call_deferred();1975}1976}19771978void VisualShaderEditor::_update_options_menu_deferred() {1979_update_options_menu();19801981_block_update_options_menu = false;1982}19831984void VisualShaderEditor::_rebuild_shader_deferred() {1985if (visual_shader.is_valid()) {1986visual_shader->rebuild();1987}19881989_block_rebuild_shader = false;1990}19911992bool VisualShaderEditor::_is_available(int p_mode) {1993int current_mode = edit_type->get_selected();19941995if (p_mode != -1) {1996switch (current_mode) {1997case 0: // Vertex / Emit1998current_mode = 1;1999break;2000case 1: // Fragment / Process2001current_mode = 2;2002break;2003case 2: // Light / Collide2004current_mode = 4;2005break;2006default:2007break;2008}2009}20102011return (p_mode == -1 || (p_mode & current_mode) != 0);2012}20132014bool VisualShaderEditor::_update_preview_parameter_tree() {2015bool found = false;2016bool use_filter = !param_filter_name.is_empty();20172018parameters->clear();2019TreeItem *root = parameters->create_item();20202021for (const KeyValue<String, PropertyInfo> &prop : parameter_props) {2022String param_name = prop.value.name;2023if (use_filter && !param_name.containsn(param_filter_name)) {2024continue;2025}20262027TreeItem *item = parameters->create_item(root);2028item->set_text(0, param_name);2029item->set_meta("id", param_name);20302031if (param_name == selected_param_id) {2032parameters->set_selected(item);2033found = true;2034}20352036if (prop.value.type == Variant::OBJECT) {2037item->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));2038} else {2039item->set_icon(0, get_editor_theme_icon(Variant::get_type_name(prop.value.type)));2040}2041}20422043return found;2044}20452046void VisualShaderEditor::_preview_tools_menu_option(int p_idx) {2047ShaderMaterial *src_mat = nullptr;20482049if (p_idx == COPY_PARAMS_FROM_MATERIAL || p_idx == PASTE_PARAMS_TO_MATERIAL) {2050for (int i = EditorNode::get_singleton()->get_editor_selection_history()->get_path_size() - 1; i >= 0; i--) {2051Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_path_object(i));2052ShaderMaterial *src_mat2;2053if (!object) {2054continue;2055}2056if (object->has_method("get_material_override")) { // Trying to get material from MeshInstance.2057src_mat2 = Object::cast_to<ShaderMaterial>(object->call("get_material_override"));2058} else if (object->has_method("get_material")) { // From CanvasItem/Node2D.2059src_mat2 = Object::cast_to<ShaderMaterial>(object->call("get_material"));2060} else {2061src_mat2 = Object::cast_to<ShaderMaterial>(object);2062}20632064if (src_mat2 && src_mat2->get_shader().is_valid() && src_mat2->get_shader() == visual_shader) {2065src_mat = src_mat2;2066break;2067}2068}2069}20702071switch (p_idx) {2072case COPY_PARAMS_FROM_MATERIAL:2073if (src_mat) {2074EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2075undo_redo->create_action(TTR("Copy Preview Shader Parameters From Material"));20762077List<PropertyInfo> params;2078preview_material->get_shader()->get_shader_uniform_list(¶ms);2079for (const PropertyInfo &E : params) {2080undo_redo->add_do_method(visual_shader.ptr(), "_set_preview_shader_parameter", E.name, src_mat->get_shader_parameter(E.name));2081undo_redo->add_undo_method(visual_shader.ptr(), "_set_preview_shader_parameter", E.name, preview_material->get_shader_parameter(E.name));2082}20832084undo_redo->commit_action();2085}2086break;2087case PASTE_PARAMS_TO_MATERIAL:2088if (src_mat) {2089EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2090undo_redo->create_action(TTR("Paste Preview Shader Parameters To Material"));20912092List<PropertyInfo> params;2093preview_material->get_shader()->get_shader_uniform_list(¶ms);2094for (const PropertyInfo &E : params) {2095undo_redo->add_do_method(src_mat, "set_shader_parameter", E.name, preview_material->get_shader_parameter(E.name));2096undo_redo->add_undo_method(src_mat, "set_shader_parameter", E.name, src_mat->get_shader_parameter(E.name));2097}20982099undo_redo->commit_action();2100}2101break;2102default:2103break;2104}2105}21062107void VisualShaderEditor::_clear_preview_param() {2108selected_param_id = "";2109current_prop = nullptr;21102111if (param_vbox2->get_child_count() > 0) {2112param_vbox2->remove_child(param_vbox2->get_child(0));2113}21142115param_vbox->hide();2116}21172118void VisualShaderEditor::_update_preview_parameter_list() {2119material_editor->edit(preview_material.ptr(), env);21202121List<PropertyInfo> properties;2122RenderingServer::get_singleton()->get_shader_parameter_list(visual_shader->get_rid(), &properties);21232124HashSet<String> params_to_remove;2125for (const KeyValue<String, PropertyInfo> &E : parameter_props) {2126params_to_remove.insert(E.key);2127}2128parameter_props.clear();21292130for (const PropertyInfo &prop : properties) {2131String param_name = prop.name;21322133if (visual_shader->_has_preview_shader_parameter(param_name)) {2134preview_material->set_shader_parameter(param_name, visual_shader->_get_preview_shader_parameter(param_name));2135} else {2136preview_material->set_shader_parameter(param_name, RenderingServer::get_singleton()->shader_get_parameter_default(visual_shader->get_rid(), param_name));2137}21382139parameter_props.insert(param_name, prop);2140params_to_remove.erase(param_name);21412142if (param_name == selected_param_id) {2143current_prop->update_property();2144current_prop->update_editor_property_status();2145current_prop->update_cache();2146}2147}21482149_update_preview_parameter_tree();21502151// Removes invalid parameters.2152for (const String ¶m_name : params_to_remove) {2153preview_material->set_shader_parameter(param_name, Variant());21542155if (visual_shader->_has_preview_shader_parameter(param_name)) {2156visual_shader->_set_preview_shader_parameter(param_name, Variant());2157}21582159if (param_name == selected_param_id) {2160_clear_preview_param();2161}2162}2163}21642165void VisualShaderEditor::_update_nodes() {2166clear_custom_types();2167Dictionary added;21682169// Add GDScript classes.2170{2171LocalVector<StringName> class_list;2172ScriptServer::get_global_class_list(class_list);21732174for (const StringName &class_name : class_list) {2175if (ScriptServer::get_global_class_native_base(class_name) == "VisualShaderNodeCustom") {2176String script_path = ScriptServer::get_global_class_path(class_name);2177Ref<Resource> res = ResourceLoader::load(script_path);2178ERR_CONTINUE(res.is_null());2179ERR_CONTINUE(!res->is_class("Script"));2180Ref<Script> scr = Ref<Script>(res);21812182Ref<VisualShaderNodeCustom> ref;2183ref.instantiate();2184ref->set_script(scr);2185if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {2186continue;2187}2188Dictionary dict = get_custom_node_data(ref);2189dict["type"] = String();21902191String key;2192key = String(dict["category"]) + "/" + String(dict["name"]);21932194added[key] = dict;2195}2196}2197}21982199// Add GDExtension classes.2200{2201LocalVector<StringName> class_list;2202ClassDB::get_class_list(class_list);22032204for (const StringName &class_name : class_list) {2205if (ClassDB::get_parent_class(class_name) == "VisualShaderNodeCustom") {2206Object *instance = ClassDB::instantiate(class_name);2207Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance);2208ERR_CONTINUE(ref.is_null());2209if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {2210continue;2211}2212Dictionary dict = get_custom_node_data(ref);2213dict["type"] = class_name;2214dict["script"] = Ref<Script>();22152216String key;2217key = String(dict["category"]) + "/" + String(dict["name"]);22182219added[key] = dict;2220}2221}2222}22232224// Disables not-supported copied items.2225{2226for (CopyItem &item : copy_items_buffer) {2227Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(item.node.ptr());22282229if (custom.is_valid()) {2230if (!custom->is_available(visual_shader->get_mode(), get_current_shader_type())) {2231item.disabled = true;2232} else {2233item.disabled = false;2234}2235} else {2236for (int i = 0; i < add_options.size(); i++) {2237if (add_options[i].type == item.node->get_class_name()) {2238if ((add_options[i].func != visual_shader->get_mode() && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {2239item.disabled = true;2240} else {2241item.disabled = false;2242}2243break;2244}2245}2246}2247}2248}22492250LocalVector<Variant> keys = added.get_key_list();2251keys.sort_custom<StringLikeVariantOrder>();22522253for (const Variant &key : keys) {2254const Dictionary &value = (Dictionary)added[key];22552256add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);2257}22582259_update_options_menu();2260}22612262String VisualShaderEditor::_get_description(int p_idx) {2263return add_options[p_idx].description;2264}22652266void VisualShaderEditor::_update_options_menu() {2267node_desc->set_text("");2268highend_label->set_visible(false);2269members_dialog->get_ok_button()->set_disabled(true);22702271members->clear();2272TreeItem *root = members->create_item();22732274String filter = node_filter->get_text().strip_edges();2275bool use_filter = !filter.is_empty();22762277bool is_first_item = true;22782279Color unsupported_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));2280Color supported_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor));22812282static bool low_driver = GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility";22832284HashMap<String, TreeItem *> folders;22852286int current_func = -1;22872288if (visual_shader.is_valid()) {2289current_func = visual_shader->get_mode();2290}22912292Vector<AddOption> custom_options;2293Vector<AddOption> embedded_options;22942295static Vector<String> type_filter_exceptions;2296if (type_filter_exceptions.is_empty()) {2297type_filter_exceptions.append("VisualShaderNodeExpression");2298type_filter_exceptions.append("VisualShaderNodeReroute");2299}23002301for (int i = 0; i < add_options.size(); i++) {2302if (!use_filter || add_options[i].name.containsn(filter)) {2303// port type filtering2304if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX || members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {2305Ref<VisualShaderNode> vsn;2306int check_result = 0;23072308if (!add_options[i].is_custom) {2309vsn = Ref<VisualShaderNode>(Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[i].type)));2310if (vsn.is_null()) {2311continue;2312}23132314if (type_filter_exceptions.has(add_options[i].type)) {2315check_result = 1;2316}23172318Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(vsn.ptr());2319if (input.is_valid()) {2320input->set_shader_mode(visual_shader->get_mode());2321input->set_shader_type(get_current_shader_type());2322if (!add_options[i].ops.is_empty() && add_options[i].ops[0].is_string()) {2323input->set_input_name((String)add_options[i].ops[0]);2324}2325}23262327Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(vsn.ptr());2328if (expression.is_valid()) {2329if (members_input_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {2330check_result = -1; // expressions creates a port with required type automatically (except for sampler output)2331}2332}23332334Ref<VisualShaderNodeParameterRef> parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn.ptr());2335if (parameter_ref.is_valid() && parameter_ref->is_shader_valid()) {2336check_result = -1;23372338if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {2339for (int j = 0; j < parameter_ref->get_parameters_count(); j++) {2340if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(j), members_input_port_type)) {2341check_result = 1;2342break;2343}2344}2345}2346}2347} else {2348check_result = 1;2349}23502351if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX) {2352if (check_result == 0) {2353for (int j = 0; j < vsn->get_input_port_count(); j++) {2354if (visual_shader->is_port_types_compatible(vsn->get_input_port_type(j), members_output_port_type)) {2355check_result = 1;2356break;2357}2358}2359}23602361if (check_result != 1) {2362continue;2363}2364}2365if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {2366if (check_result == 0) {2367for (int j = 0; j < vsn->get_output_port_count(); j++) {2368if (visual_shader->is_port_types_compatible(vsn->get_output_port_type(j), members_input_port_type)) {2369check_result = 1;2370break;2371}2372}2373}23742375if (check_result != 1) {2376continue;2377}2378}2379}2380if ((add_options[i].func != current_func && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {2381continue;2382}2383add_options[i].temp_idx = i; // save valid id2384if (add_options[i].is_custom) {2385custom_options.push_back(add_options[i]);2386} else {2387embedded_options.push_back(add_options[i]);2388}2389}2390}2391Vector<AddOption> options;2392SortArray<AddOption, _OptionComparator> sorter;2393sorter.sort(custom_options.ptrw(), custom_options.size());23942395options.append_array(custom_options);2396options.append_array(embedded_options);23972398for (int i = 0; i < options.size(); i++) {2399String path = options[i].category;2400Vector<String> subfolders = path.split("/");2401TreeItem *category = nullptr;24022403if (!folders.has(path)) {2404category = root;2405String path_temp = "";2406for (int j = 0; j < subfolders.size(); j++) {2407path_temp += subfolders[j];2408if (!folders.has(path_temp)) {2409category = members->create_item(category);2410category->set_selectable(0, false);2411category->set_collapsed(!use_filter);2412category->set_text(0, subfolders[j]);2413folders.insert(path_temp, category);2414} else {2415category = folders[path_temp];2416}2417}2418} else {2419category = folders[path];2420}24212422TreeItem *item = members->create_item(category);2423if (options[i].highend && low_driver) {2424item->set_custom_color(0, unsupported_color);2425} else if (options[i].highend) {2426item->set_custom_color(0, supported_color);2427}2428item->set_text(0, options[i].name);2429if (is_first_item && use_filter) {2430item->select(0);2431node_desc->set_text(options[i].description);2432is_first_item = false;24332434members_dialog->get_ok_button()->set_disabled(false);2435}2436switch (options[i].return_type) {2437case VisualShaderNode::PORT_TYPE_SCALAR:2438item->set_icon(0, get_editor_theme_icon(SNAME("float")));2439break;2440case VisualShaderNode::PORT_TYPE_SCALAR_INT:2441item->set_icon(0, get_editor_theme_icon(SNAME("int")));2442break;2443case VisualShaderNode::PORT_TYPE_SCALAR_UINT:2444item->set_icon(0, get_editor_theme_icon(SNAME("uint")));2445break;2446case VisualShaderNode::PORT_TYPE_VECTOR_2D:2447item->set_icon(0, get_editor_theme_icon(SNAME("Vector2")));2448break;2449case VisualShaderNode::PORT_TYPE_VECTOR_3D:2450item->set_icon(0, get_editor_theme_icon(SNAME("Vector3")));2451break;2452case VisualShaderNode::PORT_TYPE_VECTOR_4D:2453item->set_icon(0, get_editor_theme_icon(SNAME("Vector4")));2454break;2455case VisualShaderNode::PORT_TYPE_BOOLEAN:2456item->set_icon(0, get_editor_theme_icon(SNAME("bool")));2457break;2458case VisualShaderNode::PORT_TYPE_TRANSFORM:2459item->set_icon(0, get_editor_theme_icon(SNAME("Transform3D")));2460break;2461case VisualShaderNode::PORT_TYPE_SAMPLER:2462item->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));2463break;2464default:2465break;2466}2467item->set_meta("id", options[i].temp_idx);2468}2469}24702471void VisualShaderEditor::_set_mode(int p_which) {2472if (p_which == VisualShader::MODE_SKY) {2473edit_type_standard->set_visible(false);2474edit_type_particles->set_visible(false);2475edit_type_sky->set_visible(true);2476edit_type_fog->set_visible(false);2477edit_type_texture_blit->set_visible(false);2478edit_type = edit_type_sky;2479custom_mode_box->set_visible(false);2480varying_button->hide();2481mode = MODE_FLAGS_SKY;2482} else if (p_which == VisualShader::MODE_FOG) {2483edit_type_standard->set_visible(false);2484edit_type_particles->set_visible(false);2485edit_type_sky->set_visible(false);2486edit_type_fog->set_visible(true);2487edit_type_texture_blit->set_visible(false);2488edit_type = edit_type_fog;2489custom_mode_box->set_visible(false);2490varying_button->hide();2491mode = MODE_FLAGS_FOG;2492} else if (p_which == VisualShader::MODE_PARTICLES) {2493edit_type_standard->set_visible(false);2494edit_type_particles->set_visible(true);2495edit_type_sky->set_visible(false);2496edit_type_fog->set_visible(false);2497edit_type_texture_blit->set_visible(false);2498edit_type = edit_type_particles;2499if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {2500custom_mode_box->set_visible(false);2501} else {2502custom_mode_box->set_visible(true);2503}2504varying_button->hide();2505mode = MODE_FLAGS_PARTICLES;2506} else if (p_which == VisualShader::MODE_TEXTURE_BLIT) {2507edit_type_standard->set_visible(false);2508edit_type_particles->set_visible(false);2509edit_type_sky->set_visible(false);2510edit_type_fog->set_visible(false);2511edit_type_texture_blit->set_visible(true);2512edit_type = edit_type_texture_blit;2513if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {2514custom_mode_box->set_visible(false);2515} else {2516custom_mode_box->set_visible(true);2517}2518varying_button->hide();2519mode = MODE_FLAGS_TEXTURE_BLIT;2520} else {2521edit_type_particles->set_visible(false);2522edit_type_standard->set_visible(true);2523edit_type_sky->set_visible(false);2524edit_type_fog->set_visible(false);2525edit_type_texture_blit->set_visible(false);2526edit_type = edit_type_standard;2527custom_mode_box->set_visible(false);2528varying_button->show();2529mode = MODE_FLAGS_SPATIAL_CANVASITEM;2530}25312532const String id_string = _get_cache_id_string();25332534int default_type = VisualShader::TYPE_VERTEX;2535int upper_type = VisualShader::TYPE_START;2536if (mode & MODE_FLAGS_PARTICLES) {2537default_type = VisualShader::TYPE_START;2538upper_type = VisualShader::TYPE_SKY;2539} else if (mode & MODE_FLAGS_SKY) {2540default_type = VisualShader::TYPE_SKY;2541upper_type = VisualShader::TYPE_FOG;2542} else if (mode & MODE_FLAGS_FOG) {2543default_type = VisualShader::TYPE_FOG;2544upper_type = VisualShader::TYPE_TEXTURE_BLIT;2545} else if (mode & MODE_FLAGS_TEXTURE_BLIT) {2546default_type = VisualShader::TYPE_TEXTURE_BLIT;2547upper_type = VisualShader::TYPE_MAX;2548}25492550int saved_type = vs_editor_cache->get_value(id_string, "edited_type", default_type);2551if (saved_type >= upper_type || saved_type < default_type) {2552saved_type = default_type;2553}25542555if (mode & MODE_FLAGS_PARTICLES && saved_type - default_type >= 3) {2556edit_type->select(saved_type - default_type - 3);2557custom_mode_box->set_pressed(true);2558} else {2559edit_type->select(saved_type - default_type);2560}2561set_current_shader_type((VisualShader::Type)saved_type);2562}25632564Size2 VisualShaderEditor::get_minimum_size() const {2565return Size2(10, 200);2566}25672568void VisualShaderEditor::update_toggle_files_button() {2569ERR_FAIL_NULL(toggle_files_list);2570bool forward = toggle_files_list->is_visible() == is_layout_rtl();2571toggle_files_button->set_button_icon(get_editor_theme_icon(forward ? SNAME("Forward") : SNAME("Back")));2572toggle_files_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Files Panel"), ED_GET_SHORTCUT("script_editor/toggle_files_panel")->get_as_text()));2573}25742575void VisualShaderEditor::_draw_color_over_button(Object *p_obj, Color p_color) {2576Button *button = Object::cast_to<Button>(p_obj);2577if (!button) {2578return;2579}25802581Ref<StyleBox> normal = get_theme_stylebox(CoreStringName(normal), SNAME("Button"));2582button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);2583}25842585void VisualShaderEditor::_update_parameters(bool p_update_refs) {2586VisualShaderNodeParameterRef::clear_parameters(visual_shader->get_rid());25872588for (int t = 0; t < VisualShader::TYPE_MAX; t++) {2589Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t);2590for (int i = 0; i < tnodes.size(); i++) {2591Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]);2592Ref<VisualShaderNodeParameter> parameter = vsnode;25932594if (parameter.is_valid()) {2595Ref<VisualShaderNodeFloatParameter> float_parameter = vsnode;2596Ref<VisualShaderNodeIntParameter> int_parameter = vsnode;2597Ref<VisualShaderNodeUIntParameter> uint_parameter = vsnode;2598Ref<VisualShaderNodeVec2Parameter> vec2_parameter = vsnode;2599Ref<VisualShaderNodeVec3Parameter> vec3_parameter = vsnode;2600Ref<VisualShaderNodeVec4Parameter> vec4_parameter = vsnode;2601Ref<VisualShaderNodeColorParameter> color_parameter = vsnode;2602Ref<VisualShaderNodeBooleanParameter> boolean_parameter = vsnode;2603Ref<VisualShaderNodeTransformParameter> transform_parameter = vsnode;26042605VisualShaderNodeParameterRef::ParameterType parameter_type;2606if (float_parameter.is_valid()) {2607parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_FLOAT;2608} else if (int_parameter.is_valid()) {2609parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_INT;2610} else if (uint_parameter.is_valid()) {2611parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_UINT;2612} else if (boolean_parameter.is_valid()) {2613parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_BOOLEAN;2614} else if (vec2_parameter.is_valid()) {2615parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR2;2616} else if (vec3_parameter.is_valid()) {2617parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR3;2618} else if (vec4_parameter.is_valid()) {2619parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR4;2620} else if (transform_parameter.is_valid()) {2621parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_TRANSFORM;2622} else if (color_parameter.is_valid()) {2623parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_COLOR;2624} else {2625parameter_type = VisualShaderNodeParameterRef::UNIFORM_TYPE_SAMPLER;2626}2627VisualShaderNodeParameterRef::add_parameter(visual_shader->get_rid(), parameter->get_parameter_name(), parameter_type);2628}2629}2630}2631if (p_update_refs) {2632graph_plugin->update_parameter_refs();2633}2634}26352636void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) {2637EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2638for (int i = 0; i < VisualShader::TYPE_MAX; i++) {2639VisualShader::Type type = VisualShader::Type(i);26402641Vector<int> nodes = visual_shader->get_node_list(type);2642for (int j = 0; j < nodes.size(); j++) {2643if (j > 0) {2644Ref<VisualShaderNodeParameterRef> ref = visual_shader->get_node(type, nodes[j]);2645if (ref.is_valid()) {2646if (p_deleted_names.has(ref->get_parameter_name())) {2647undo_redo->add_do_method(ref.ptr(), "set_parameter_name", "[None]");2648undo_redo->add_undo_method(ref.ptr(), "set_parameter_name", ref->get_parameter_name());2649undo_redo->add_do_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);2650undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);2651}2652}2653}2654}2655}2656}26572658void VisualShaderEditor::_update_graph() {2659if (visual_shader.is_null()) {2660return;2661}26622663if (!is_inside_tree()) {2664return;2665}26662667VisualShader::Type type = get_current_shader_type();26682669graph->clear_connections();2670// Remove all nodes.2671for (int i = 0; i < graph->get_child_count(); i++) {2672if (Object::cast_to<GraphElement>(graph->get_child(i))) {2673Node *node = graph->get_child(i);2674graph->remove_child(node);2675memdelete(node);2676i--;2677}2678}26792680List<VisualShader::Connection> node_connections;2681visual_shader->get_node_connections(type, &node_connections);2682graph_plugin->set_connections(node_connections);26832684Vector<int> nodes = visual_shader->get_node_list(type);26852686_update_parameters(false);2687_update_varyings();26882689graph_plugin->clear_links();2690graph_plugin->update_theme();26912692for (int n_i = 0; n_i < nodes.size(); n_i++) {2693// Update frame related stuff later since we need to have all nodes in the graph.2694graph_plugin->add_node(type, nodes[n_i], false, false);2695}26962697for (const VisualShader::Connection &E : node_connections) {2698int from = E.from_node;2699int from_idx = E.from_port;2700int to = E.to_node;2701int to_idx = E.to_port;27022703graph->connect_node(itos(from), from_idx, itos(to), to_idx);2704}27052706// Attach nodes to frames.2707for (int node_id : nodes) {2708Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);2709ERR_CONTINUE_MSG(vsnode.is_null(), "Node is null.");27102711if (vsnode->get_frame() != -1) {2712int frame_name = vsnode->get_frame();2713graph->attach_graph_element_to_frame(itos(node_id), itos(frame_name));2714}2715}27162717float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");2718graph->set_minimap_opacity(graph_minimap_opacity);2719float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");2720graph->set_connection_lines_curvature(graph_lines_curvature);2721}27222723void VisualShaderEditor::_restore_editor_state() {2724const String id_string = _get_cache_id_string();27252726const String offset_cache_key = _get_cache_key("offset");2727const String zoom_cache_key = _get_cache_key("zoom");2728const Vector2 saved_scroll_offset = vs_editor_cache->get_value(id_string, offset_cache_key, Vector2());2729const real_t saved_zoom = vs_editor_cache->get_value(id_string, zoom_cache_key, 1.0);27302731// Setting the scroll offset needs to be further deferred because it requires min/max scroll offset to be final (as it gets clamped).2732callable_mp(graph, &GraphEdit::set_zoom).call_deferred(saved_zoom);2733callable_mp(graph, &GraphEdit::set_scroll_offset).call_deferred(saved_scroll_offset);27342735shader_fully_loaded = true;2736}27372738String VisualShaderEditor::_get_cache_id_string() const {2739String id_string = visual_shader->get_path();2740const ResourceUID::ID uid = EditorFileSystem::get_singleton()->get_file_uid(id_string);2741if (uid != ResourceUID::INVALID_ID) {2742id_string = ResourceUID::get_singleton()->id_to_text(uid);2743}2744return id_string;2745}27462747String VisualShaderEditor::_get_cache_key(const String &p_prop_name) const {2748const int type = get_current_shader_type();2749return "type" + itos(type) + ":" + p_prop_name;2750}27512752void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) {2753VisualShader::Type type = get_current_shader_type();2754Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);2755if (node.is_null()) {2756return;2757}27582759EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2760undo_redo->create_action(TTR("Add Input Port"));2761undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name);2762undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port);2763undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2764undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2765undo_redo->commit_action();2766}27672768void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_type, const String &p_name) {2769VisualShader::Type type = get_current_shader_type();2770Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2771if (node.is_null()) {2772return;2773}27742775EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2776undo_redo->create_action(TTR("Add Output Port"));2777undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name);2778undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port);2779undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2780undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2781undo_redo->commit_action();2782}27832784void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_port) {2785VisualShader::Type type = get_current_shader_type();2786Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2787if (node.is_null()) {2788return;2789}27902791EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2792undo_redo->create_action(TTR("Change Input Port Type"));2793undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type);2794undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port));2795undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2796undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2797undo_redo->commit_action();2798}27992800void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_port) {2801VisualShader::Type type = get_current_shader_type();2802Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2803if (node.is_null()) {2804return;2805}28062807EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2808undo_redo->create_action(TTR("Change Output Port Type"));2809undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type);2810undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port));2811undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2812undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2813undo_redo->commit_action();2814}28152816void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p_line_edit, int p_node_id, int p_port_id) {2817VisualShader::Type type = get_current_shader_type();28182819Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);2820ERR_FAIL_COND(node.is_null());28212822String prev_name = node->get_input_port_name(p_port_id);2823if (prev_name == p_text) {2824return;2825}28262827LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);2828ERR_FAIL_NULL(line_edit);28292830String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, false);2831if (validated_name.is_empty() || prev_name == validated_name) {2832line_edit->set_text(node->get_input_port_name(p_port_id));2833return;2834}28352836EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2837undo_redo->create_action(TTR("Change Input Port Name"));2838undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, validated_name);2839undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id));2840undo_redo->commit_action();2841}28422843void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *p_line_edit, int p_node_id, int p_port_id) {2844VisualShader::Type type = get_current_shader_type();28452846Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);2847ERR_FAIL_COND(node.is_null());28482849String prev_name = node->get_output_port_name(p_port_id);2850if (prev_name == p_text) {2851return;2852}28532854LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);2855ERR_FAIL_NULL(line_edit);28562857String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, true);2858if (validated_name.is_empty() || prev_name == validated_name) {2859line_edit->set_text(node->get_output_port_name(p_port_id));2860return;2861}28622863EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2864undo_redo->create_action(TTR("Change Output Port Name"));2865undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, validated_name);2866undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, prev_name);2867undo_redo->commit_action();2868}28692870void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expand) {2871VisualShader::Type type = get_current_shader_type();28722873Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);2874ERR_FAIL_COND(node.is_null());28752876EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2877if (p_expand) {2878undo_redo->create_action(TTR("Expand Output Port"));2879} else {2880undo_redo->create_action(TTR("Shrink Output Port"));2881}28822883undo_redo->add_do_method(node.ptr(), "_set_output_port_expanded", p_port, p_expand);2884undo_redo->add_undo_method(node.ptr(), "_set_output_port_expanded", p_port, !p_expand);28852886int type_size = 0;2887switch (node->get_output_port_type(p_port)) {2888case VisualShaderNode::PORT_TYPE_VECTOR_2D: {2889type_size = 2;2890} break;2891case VisualShaderNode::PORT_TYPE_VECTOR_3D: {2892type_size = 3;2893} break;2894case VisualShaderNode::PORT_TYPE_VECTOR_4D: {2895type_size = 4;2896} break;2897default:2898break;2899}29002901List<VisualShader::Connection> conns;2902visual_shader->get_node_connections(type, &conns);29032904for (const VisualShader::Connection &E : conns) {2905int cn_from_node = E.from_node;2906int cn_from_port = E.from_port;2907int cn_to_node = E.to_node;2908int cn_to_port = E.to_port;29092910if (cn_from_node == p_node) {2911if (p_expand) {2912if (cn_from_port > p_port) { // reconnect ports after expanded ports2913undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2914undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29152916undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2917undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29182919undo_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);2920undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);29212922undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);2923undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);2924}2925} else {2926if (cn_from_port > p_port + type_size) { // reconnect ports after expanded ports2927undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2928undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29292930undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2931undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29322933undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);2934undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);29352936undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);2937undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);2938} else if (cn_from_port > p_port) { // disconnect component ports2939undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2940undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29412942undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2943undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2944}2945}2946}2947}29482949int preview_port = node->get_output_port_for_preview();2950if (p_expand) {2951if (preview_port > p_port) {2952undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port + type_size);2953undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);2954}2955} else {2956if (preview_port > p_port + type_size) {2957undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - type_size);2958undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);2959}2960}29612962undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);2963undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);2964undo_redo->commit_action();2965}29662967void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {2968VisualShader::Type type = get_current_shader_type();2969Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);2970if (node.is_null()) {2971return;2972}29732974EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();2975undo_redo->create_action(TTR("Remove Input Port"));29762977List<VisualShader::Connection> conns;2978visual_shader->get_node_connections(type, &conns);2979for (const VisualShader::Connection &E : conns) {2980int cn_from_node = E.from_node;2981int cn_from_port = E.from_port;2982int cn_to_node = E.to_node;2983int cn_to_port = E.to_port;29842985if (cn_to_node == p_node) {2986if (cn_to_port == p_port) {2987undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2988undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29892990undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2991undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2992} else if (cn_to_port > p_port) {2993undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2994undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29952996undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);2997undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);29982999undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);3000undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);30013002undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);3003undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);3004}3005}3006}30073008undo_redo->add_do_method(node.ptr(), "remove_input_port", p_port);3009undo_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));30103011undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);3012undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);30133014undo_redo->commit_action();3015}30163017void VisualShaderEditor::_remove_output_port(int p_node, int p_port) {3018VisualShader::Type type = get_current_shader_type();3019Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);3020if (node.is_null()) {3021return;3022}30233024EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3025undo_redo->create_action(TTR("Remove Output Port"));30263027List<VisualShader::Connection> conns;3028visual_shader->get_node_connections(type, &conns);3029for (const VisualShader::Connection &E : conns) {3030int cn_from_node = E.from_node;3031int cn_from_port = E.from_port;3032int cn_to_node = E.to_node;3033int cn_to_port = E.to_port;30343035if (cn_from_node == p_node) {3036if (cn_from_port == p_port) {3037undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3038undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);30393040undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3041undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3042} else if (cn_from_port > p_port) {3043undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3044undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);30453046undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);3047undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);30483049undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);3050undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);30513052undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);3053undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);3054}3055}3056}30573058int preview_port = node->get_output_port_for_preview();3059if (preview_port != -1) {3060if (preview_port == p_port) {3061undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", -1);3062undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);3063} else if (preview_port > p_port) {3064undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - 1);3065undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);3066}3067}30683069undo_redo->add_do_method(node.ptr(), "remove_output_port", p_port);3070undo_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));30713072undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);3073undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);30743075undo_redo->commit_action();3076}30773078void VisualShaderEditor::_expression_focus_out(Object *p_code_edit, int p_node) {3079VisualShader::Type type = get_current_shader_type();3080Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);3081if (node.is_null()) {3082return;3083}30843085CodeEdit *expression_box = Object::cast_to<CodeEdit>(p_code_edit);30863087if (node->get_expression() == expression_box->get_text()) {3088return;3089}30903091EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3092undo_redo->create_action(TTR("Set VisualShader Expression"));3093undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text());3094undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression());3095undo_redo->add_do_method(graph_plugin.ptr(), "set_expression", type, p_node, expression_box->get_text());3096undo_redo->add_undo_method(graph_plugin.ptr(), "set_expression", type, p_node, node->get_expression());3097undo_redo->commit_action();3098}30993100void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) {3101VisualShader::Type type = VisualShader::Type(p_type);3102Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(type, p_node);3103if (node.is_null()) {3104return;3105}31063107Size2 size = p_size;3108if (!node->is_allow_v_resize()) {3109size.y = 0;3110}31113112node->set_size(size);31133114if (get_current_shader_type() == type) {3115Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(node.ptr());3116Control *text_box = nullptr;3117if (expression_node.is_valid()) {3118text_box = expression_node->is_ctrl_pressed(0);3119if (text_box) {3120text_box->set_custom_minimum_size(Size2(0, 0));3121}3122}31233124GraphElement *graph_element = nullptr;3125Node *node2 = graph->get_node(itos(p_node));3126graph_element = Object::cast_to<GraphElement>(node2);3127if (!graph_element) {3128return;3129}31303131graph_element->set_size(size);3132}31333134// Update all parent frames.3135graph_plugin->update_frames(type, p_node);3136}31373138// Called once after the node was resized.3139void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, int p_node) {3140Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(VisualShader::Type(p_type), p_node);3141if (node.is_null()) {3142return;3143}31443145GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_node(itos(p_node)));3146if (!graph_element) {3147return;3148}31493150Size2 size = graph_element->get_size();31513152EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3153undo_redo->create_action(TTR("Resize VisualShader Node"));3154undo_redo->add_do_method(this, "_set_node_size", p_type, p_node, size);3155undo_redo->add_undo_method(this, "_set_node_size", p_type, p_node, node->get_size());3156undo_redo->commit_action();3157}31583159void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {3160VisualShader::Type type = get_current_shader_type();3161Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);3162if (node.is_null()) {3163return;3164}3165int prev_port = node->get_output_port_for_preview();3166if (node->get_output_port_for_preview() == p_port) {3167p_port = -1; //toggle it3168}3169EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3170undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview"));3171undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port);3172undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port);3173undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, p_node);3174undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, p_node);3175undo_redo->commit_action();3176}31773178void VisualShaderEditor::_frame_title_popup_show(const Point2 &p_position, int p_node_id) {3179VisualShader::Type type = get_current_shader_type();3180Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);3181if (node.is_null()) {3182return;3183}3184frame_title_change_edit->set_text(node->get_title());3185frame_title_change_popup->set_meta("id", p_node_id);3186frame_title_change_popup->set_position(p_position);3187frame_title_change_popup->popup();31883189// Select current text.3190frame_title_change_edit->grab_focus();3191}31923193void VisualShaderEditor::_frame_title_text_changed(const String &p_new_text) {3194frame_title_change_edit->reset_size();3195frame_title_change_popup->reset_size();3196}31973198void VisualShaderEditor::_frame_title_text_submitted(const String &p_new_text) {3199frame_title_change_popup->hide();3200}32013202void VisualShaderEditor::_frame_title_popup_focus_out() {3203frame_title_change_popup->hide();3204}32053206void VisualShaderEditor::_frame_title_popup_hide() {3207int node_id = (int)frame_title_change_popup->get_meta("id", -1);3208ERR_FAIL_COND(node_id == -1);32093210VisualShader::Type type = get_current_shader_type();3211Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, node_id);32123213ERR_FAIL_COND(node.is_null());32143215if (node->get_title() == frame_title_change_edit->get_text()) {3216return; // nothing changed - ignored3217}3218EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3219undo_redo->create_action(TTR("Set Frame Title"));3220undo_redo->add_do_method(node.ptr(), "set_title", frame_title_change_edit->get_text());3221undo_redo->add_undo_method(node.ptr(), "set_title", node->get_title());3222undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);3223undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);3224undo_redo->commit_action();3225}32263227void VisualShaderEditor::_frame_color_enabled_changed(int p_node_id) {3228int item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_COLOR);32293230// The new state.3231bool tint_color_enabled = !popup_menu->is_item_checked(item_index);32323233popup_menu->set_item_checked(item_index, tint_color_enabled);3234int frame_color_item_idx = popup_menu->get_item_index(NodeMenuOptions::SET_FRAME_COLOR);3235if (tint_color_enabled && frame_color_item_idx == -1) {3236popup_menu->add_item(TTR("Set Tint Color"), NodeMenuOptions::SET_FRAME_COLOR);3237} else if (!tint_color_enabled && frame_color_item_idx != -1) {3238popup_menu->remove_item(frame_color_item_idx);3239}32403241VisualShader::Type type = get_current_shader_type();3242Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);32433244ERR_FAIL_COND(node.is_null());32453246EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3247undo_redo->create_action(TTR("Toggle Frame Color"));3248undo_redo->add_do_method(node.ptr(), "set_tint_color_enabled", tint_color_enabled);3249undo_redo->add_undo_method(node.ptr(), "set_tint_color_enabled", node->is_tint_color_enabled());3250undo_redo->add_do_method(graph_plugin.ptr(), "set_frame_color_enabled", (int)type, p_node_id, tint_color_enabled);3251undo_redo->add_undo_method(graph_plugin.ptr(), "set_frame_color_enabled", (int)type, p_node_id, node->is_tint_color_enabled());3252undo_redo->commit_action();3253}32543255void VisualShaderEditor::_frame_color_popup_show(const Point2 &p_position, int p_node_id) {3256VisualShader::Type type = get_current_shader_type();3257Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);3258if (node.is_null()) {3259return;3260}3261frame_tint_color_picker->set_pick_color(node->get_tint_color());3262frame_tint_color_pick_popup->set_meta("id", p_node_id);3263frame_tint_color_pick_popup->set_position(p_position);3264frame_tint_color_pick_popup->popup();3265}32663267void VisualShaderEditor::_frame_color_confirm() {3268frame_tint_color_pick_popup->hide();3269}32703271void VisualShaderEditor::_frame_color_changed(const Color &p_color) {3272ERR_FAIL_COND(!frame_tint_color_pick_popup->has_meta("id"));3273int node_id = (int)frame_tint_color_pick_popup->get_meta("id");32743275VisualShader::Type type = get_current_shader_type();3276Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, node_id);3277ERR_FAIL_COND(node.is_null());3278node->set_tint_color(p_color);3279graph_plugin->set_frame_color(type, node_id, p_color);3280}32813282void VisualShaderEditor::_frame_color_popup_hide() {3283ERR_FAIL_COND(!frame_tint_color_pick_popup->has_meta("id"));3284int node_id = (int)frame_tint_color_pick_popup->get_meta("id");32853286VisualShader::Type type = get_current_shader_type();3287Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, node_id);3288ERR_FAIL_COND(node.is_null());32893290if (node->get_tint_color() == frame_tint_color_picker->get_pick_color()) {3291return;3292}32933294EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3295undo_redo->create_action(TTR("Set Frame Color"));3296undo_redo->add_do_method(node.ptr(), "set_tint_color", frame_tint_color_picker->get_pick_color());3297undo_redo->add_undo_method(node.ptr(), "set_tint_color", node->get_tint_color());3298undo_redo->add_do_method(graph_plugin.ptr(), "set_frame_color", (int)type, node_id, frame_tint_color_picker->get_pick_color());3299undo_redo->add_undo_method(graph_plugin.ptr(), "set_frame_color", (int)type, node_id, node->get_tint_color());3300undo_redo->commit_action();3301}33023303void VisualShaderEditor::_frame_autoshrink_enabled_changed(int p_node_id) {3304int item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);33053306bool autoshrink_enabled = popup_menu->is_item_checked(item_index);33073308popup_menu->set_item_checked(item_index, !autoshrink_enabled);33093310VisualShader::Type type = get_current_shader_type();3311Ref<VisualShaderNodeFrame> node = visual_shader->get_node(type, p_node_id);33123313ERR_FAIL_COND(node.is_null());33143315EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3316undo_redo->create_action(TTR("Toggle Auto Shrink"));3317undo_redo->add_do_method(node.ptr(), "set_autoshrink_enabled", !autoshrink_enabled);3318undo_redo->add_undo_method(node.ptr(), "set_autoshrink_enabled", autoshrink_enabled);3319undo_redo->add_do_method(graph_plugin.ptr(), "set_frame_autoshrink_enabled", (int)type, p_node_id, !autoshrink_enabled);3320undo_redo->add_undo_method(graph_plugin.ptr(), "set_frame_autoshrink_enabled", (int)type, p_node_id, autoshrink_enabled);3321undo_redo->commit_action();33223323popup_menu->hide();3324}33253326void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int p_node_id) {3327VisualShader::Type type = get_current_shader_type();33283329Ref<VisualShaderNodeParameter> node = visual_shader->get_node(type, p_node_id);3330ERR_FAIL_COND(node.is_null());33313332String validated_name = visual_shader->validate_parameter_name(p_text, node);33333334if (validated_name == node->get_parameter_name()) {3335return;3336}33373338EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3339undo_redo->create_action(TTR("Set Parameter Name"));3340undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);3341undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());3342undo_redo->add_do_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, validated_name);3343undo_redo->add_undo_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, node->get_parameter_name());3344undo_redo->add_do_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);3345undo_redo->add_undo_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);33463347undo_redo->add_do_method(this, "_update_parameters", true);3348undo_redo->add_undo_method(this, "_update_parameters", true);33493350HashSet<String> changed_names;3351changed_names.insert(node->get_parameter_name());3352_update_parameter_refs(changed_names);33533354undo_redo->commit_action();3355}33563357void VisualShaderEditor::_parameter_line_edit_focus_out(Object *line_edit, int p_node_id) {3358_parameter_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);3359}33603361void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) {3362if (!p_output) {3363_change_input_port_name(Object::cast_to<LineEdit>(line_edit)->get_text(), line_edit, p_node_id, p_port_id);3364} else {3365_change_output_port_name(Object::cast_to<LineEdit>(line_edit)->get_text(), line_edit, p_node_id, p_port_id);3366}3367}33683369void VisualShaderEditor::_port_edited(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {3370VisualShader::Type type = get_current_shader_type();3371Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node);3372ERR_FAIL_COND(vsn.is_null());33733374EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3375undo_redo->create_action(TTR("Set Input Default Port"));33763377Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());3378if (custom.is_valid()) {3379undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, p_value);3380undo_redo->add_undo_method(custom.ptr(), "_set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));3381} else {3382undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, p_value);3383undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));3384}3385undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, p_value);3386undo_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));3387undo_redo->commit_action();3388}33893390void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node, int p_port) {3391VisualShader::Type type = get_current_shader_type();3392Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, p_node);3393Variant value = vs_node->get_input_port_default_value(p_port);33943395edited_property_holder->set_edited_property(value);3396editing_node = p_node;3397editing_port = p_port;33983399if (property_editor) {3400property_editor->disconnect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));3401property_editor_popup->remove_child(property_editor);3402}34033404// TODO: Define these properties with actual PropertyInfo and feed it to the property editor widget.3405property_editor = EditorInspector::instantiate_property_editor(edited_property_holder.ptr(), value.get_type(), "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE, true);3406ERR_FAIL_NULL_MSG(property_editor, "Failed to create property editor for type: " + Variant::get_type_name(value.get_type()));34073408// Determine the best size for the popup based on the property type.3409// 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.3410Size2 popup_pref_size;3411switch (value.get_type()) {3412case Variant::VECTOR3:3413case Variant::BASIS:3414popup_pref_size.width = 320;3415break;3416case Variant::VECTOR4:3417case Variant::PLANE:3418case Variant::TRANSFORM2D:3419case Variant::TRANSFORM3D:3420case Variant::PROJECTION:3421popup_pref_size.width = 480;3422break;3423default:3424popup_pref_size.width = 180;3425break;3426}3427property_editor_popup->set_min_size(popup_pref_size * EDSCALE);34283429property_editor->set_object_and_property(edited_property_holder.ptr(), "edited_property");3430property_editor->update_property();3431property_editor->set_name_split_ratio(0);3432property_editor_popup->add_child(property_editor);34333434property_editor->connect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));34353436Button *button = Object::cast_to<Button>(p_button);3437if (button) {3438property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom());3439}3440property_editor_popup->reset_size();3441if (button) {3442property_editor_popup->popup();3443} else {3444property_editor_popup->popup_centered_ratio();3445}3446property_editor->select(0); // Focus the first focusable control.3447}34483449void VisualShaderEditor::_set_custom_node_option(int p_index, int p_node, int p_op) {3450VisualShader::Type type = get_current_shader_type();3451Ref<VisualShaderNodeCustom> node = visual_shader->get_node(type, p_node);3452if (node.is_null()) {3453return;3454}34553456EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3457undo_redo->create_action(TTR("Set Custom Node Option"));3458undo_redo->add_do_method(node.ptr(), "_set_option_index", p_op, p_index);3459undo_redo->add_undo_method(node.ptr(), "_set_option_index", p_op, node->get_option_index(p_op));3460undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);3461undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);3462undo_redo->commit_action();3463}34643465void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, const Vector<Variant> &p_ops) {3466// INPUT3467{3468VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(p_node);34693470if (input) {3471ERR_FAIL_COND(!p_ops[0].is_string());3472input->set_input_name((String)p_ops[0]);3473return;3474}3475}34763477// FLOAT_CONST3478{3479VisualShaderNodeFloatConstant *float_const = Object::cast_to<VisualShaderNodeFloatConstant>(p_node);34803481if (float_const) {3482ERR_FAIL_COND(p_ops[0].get_type() != Variant::FLOAT);3483float_const->set_constant((float)p_ops[0]);3484return;3485}3486}34873488// FLOAT_OP3489{3490VisualShaderNodeFloatOp *float_op = Object::cast_to<VisualShaderNodeFloatOp>(p_node);34913492if (float_op) {3493ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3494float_op->set_operator((VisualShaderNodeFloatOp::Operator)(int)p_ops[0]);3495return;3496}3497}34983499// FLOAT_FUNC3500{3501VisualShaderNodeFloatFunc *float_func = Object::cast_to<VisualShaderNodeFloatFunc>(p_node);35023503if (float_func) {3504ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3505float_func->set_function((VisualShaderNodeFloatFunc::Function)(int)p_ops[0]);3506return;3507}3508}35093510// VECTOR_OP3511{3512VisualShaderNodeVectorOp *vec_op = Object::cast_to<VisualShaderNodeVectorOp>(p_node);35133514if (vec_op) {3515ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3516ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);3517vec_op->set_operator((VisualShaderNodeVectorOp::Operator)(int)p_ops[0]);3518vec_op->set_op_type((VisualShaderNodeVectorOp::OpType)(int)p_ops[1]);3519return;3520}3521}35223523// VECTOR_FUNC3524{3525VisualShaderNodeVectorFunc *vec_func = Object::cast_to<VisualShaderNodeVectorFunc>(p_node);35263527if (vec_func) {3528ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3529ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);3530vec_func->set_function((VisualShaderNodeVectorFunc::Function)(int)p_ops[0]);3531vec_func->set_op_type((VisualShaderNodeVectorFunc::OpType)(int)p_ops[1]);3532return;3533}3534}35353536// COLOR_OP3537{3538VisualShaderNodeColorOp *color_op = Object::cast_to<VisualShaderNodeColorOp>(p_node);35393540if (color_op) {3541ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3542color_op->set_operator((VisualShaderNodeColorOp::Operator)(int)p_ops[0]);3543return;3544}3545}35463547// COLOR_FUNC3548{3549VisualShaderNodeColorFunc *color_func = Object::cast_to<VisualShaderNodeColorFunc>(p_node);35503551if (color_func) {3552ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3553color_func->set_function((VisualShaderNodeColorFunc::Function)(int)p_ops[0]);3554return;3555}3556}35573558// INT_OP3559{3560VisualShaderNodeIntOp *int_op = Object::cast_to<VisualShaderNodeIntOp>(p_node);35613562if (int_op) {3563ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3564int_op->set_operator((VisualShaderNodeIntOp::Operator)(int)p_ops[0]);3565return;3566}3567}35683569// INT_FUNC3570{3571VisualShaderNodeIntFunc *int_func = Object::cast_to<VisualShaderNodeIntFunc>(p_node);35723573if (int_func) {3574ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3575int_func->set_function((VisualShaderNodeIntFunc::Function)(int)p_ops[0]);3576return;3577}3578}35793580// UINT_OP3581{3582VisualShaderNodeUIntOp *uint_op = Object::cast_to<VisualShaderNodeUIntOp>(p_node);35833584if (uint_op) {3585ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3586uint_op->set_operator((VisualShaderNodeUIntOp::Operator)(int)p_ops[0]);3587return;3588}3589}35903591// UINT_FUNC3592{3593VisualShaderNodeUIntFunc *uint_func = Object::cast_to<VisualShaderNodeUIntFunc>(p_node);35943595if (uint_func) {3596ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3597uint_func->set_function((VisualShaderNodeUIntFunc::Function)(int)p_ops[0]);3598return;3599}3600}36013602// TRANSFORM_OP3603{3604VisualShaderNodeTransformOp *mat_op = Object::cast_to<VisualShaderNodeTransformOp>(p_node);36053606if (mat_op) {3607ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3608mat_op->set_operator((VisualShaderNodeTransformOp::Operator)(int)p_ops[0]);3609return;3610}3611}36123613// TRANSFORM_FUNC3614{3615VisualShaderNodeTransformFunc *mat_func = Object::cast_to<VisualShaderNodeTransformFunc>(p_node);36163617if (mat_func) {3618ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3619mat_func->set_function((VisualShaderNodeTransformFunc::Function)(int)p_ops[0]);3620return;3621}3622}36233624// VECTOR_COMPOSE3625{3626VisualShaderNodeVectorCompose *vec_compose = Object::cast_to<VisualShaderNodeVectorCompose>(p_node);36273628if (vec_compose) {3629ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3630vec_compose->set_op_type((VisualShaderNodeVectorCompose::OpType)(int)p_ops[0]);3631return;3632}3633}36343635// VECTOR_DECOMPOSE3636{3637VisualShaderNodeVectorDecompose *vec_decompose = Object::cast_to<VisualShaderNodeVectorDecompose>(p_node);36383639if (vec_decompose) {3640ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3641vec_decompose->set_op_type((VisualShaderNodeVectorDecompose::OpType)(int)p_ops[0]);3642return;3643}3644}36453646// UV_FUNC3647{3648VisualShaderNodeUVFunc *uv_func = Object::cast_to<VisualShaderNodeUVFunc>(p_node);36493650if (uv_func) {3651ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3652uv_func->set_function((VisualShaderNodeUVFunc::Function)(int)p_ops[0]);3653return;3654}3655}36563657// IS3658{3659VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(p_node);36603661if (is) {3662ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3663is->set_function((VisualShaderNodeIs::Function)(int)p_ops[0]);3664return;3665}3666}36673668// COMPARE3669{3670VisualShaderNodeCompare *cmp = Object::cast_to<VisualShaderNodeCompare>(p_node);36713672if (cmp) {3673ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3674cmp->set_function((VisualShaderNodeCompare::Function)(int)p_ops[0]);3675return;3676}3677}36783679// DISTANCE3680{3681VisualShaderNodeVectorDistance *dist = Object::cast_to<VisualShaderNodeVectorDistance>(p_node);36823683if (dist) {3684ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3685dist->set_op_type((VisualShaderNodeVectorDistance::OpType)(int)p_ops[0]);3686return;3687}3688}36893690// DERIVATIVE3691{3692VisualShaderNodeDerivativeFunc *der_func = Object::cast_to<VisualShaderNodeDerivativeFunc>(p_node);36933694if (der_func) {3695ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3696ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);3697der_func->set_function((VisualShaderNodeDerivativeFunc::Function)(int)p_ops[0]);3698der_func->set_op_type((VisualShaderNodeDerivativeFunc::OpType)(int)p_ops[1]);3699return;3700}3701}37023703// MIX3704{3705VisualShaderNodeMix *mix = Object::cast_to<VisualShaderNodeMix>(p_node);37063707if (mix) {3708ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3709mix->set_op_type((VisualShaderNodeMix::OpType)(int)p_ops[0]);3710return;3711}3712}37133714// CLAMP3715{3716VisualShaderNodeClamp *clamp_func = Object::cast_to<VisualShaderNodeClamp>(p_node);37173718if (clamp_func) {3719ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3720clamp_func->set_op_type((VisualShaderNodeClamp::OpType)(int)p_ops[0]);3721return;3722}3723}37243725// SWITCH3726{3727VisualShaderNodeSwitch *switch_func = Object::cast_to<VisualShaderNodeSwitch>(p_node);37283729if (switch_func) {3730ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3731switch_func->set_op_type((VisualShaderNodeSwitch::OpType)(int)p_ops[0]);3732return;3733}3734}37353736// FACEFORWARD3737{3738VisualShaderNodeFaceForward *face_forward = Object::cast_to<VisualShaderNodeFaceForward>(p_node);3739if (face_forward) {3740ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3741face_forward->set_op_type((VisualShaderNodeFaceForward::OpType)(int)p_ops[0]);3742return;3743}3744}37453746// LENGTH3747{3748VisualShaderNodeVectorLen *length = Object::cast_to<VisualShaderNodeVectorLen>(p_node);3749if (length) {3750ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3751length->set_op_type((VisualShaderNodeVectorLen::OpType)(int)p_ops[0]);3752return;3753}3754}37553756// SMOOTHSTEP3757{3758VisualShaderNodeSmoothStep *smooth_step_func = Object::cast_to<VisualShaderNodeSmoothStep>(p_node);37593760if (smooth_step_func) {3761ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3762smooth_step_func->set_op_type((VisualShaderNodeSmoothStep::OpType)(int)p_ops[0]);3763return;3764}3765}37663767// STEP3768{3769VisualShaderNodeStep *step_func = Object::cast_to<VisualShaderNodeStep>(p_node);37703771if (step_func) {3772ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3773step_func->set_op_type((VisualShaderNodeStep::OpType)(int)p_ops[0]);3774return;3775}3776}37773778// MULTIPLY_ADD3779{3780VisualShaderNodeMultiplyAdd *fma_func = Object::cast_to<VisualShaderNodeMultiplyAdd>(p_node);37813782if (fma_func) {3783ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3784fma_func->set_op_type((VisualShaderNodeMultiplyAdd::OpType)(int)p_ops[0]);3785}3786}37873788// REMAP3789{3790VisualShaderNodeRemap *remap_func = Object::cast_to<VisualShaderNodeRemap>(p_node);37913792if (remap_func) {3793ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3794remap_func->set_op_type((VisualShaderNodeRemap::OpType)(int)p_ops[0]);3795}3796}37973798// REFRACT3799{3800VisualShaderNodeVectorRefract *refract = Object::cast_to<VisualShaderNodeVectorRefract>(p_node);38013802if (refract) {3803ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);3804refract->set_op_type((VisualShaderNodeVectorRefract::OpType)(int)p_ops[0]);3805return;3806}3807}3808}38093810void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, const String &p_resource_path, int p_node_idx) {3811ERR_FAIL_INDEX(p_idx, add_options.size());38123813VisualShader::Type type = get_current_shader_type();38143815Ref<VisualShaderNode> vsnode;38163817bool is_custom = add_options[p_idx].is_custom;38183819if (!is_custom && !add_options[p_idx].type.is_empty()) {3820VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[p_idx].type));3821ERR_FAIL_NULL(vsn);3822if (!p_ops.is_empty()) {3823_setup_node(vsn, p_ops);3824}3825VisualShaderNodeParameterRef *parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn);3826if (parameter_ref && to_node != -1 && to_slot != -1) {3827VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);3828bool success = false;38293830for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {3831if (parameter_ref->get_port_type_by_index(i) == input_port_type) {3832parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));3833success = true;3834break;3835}3836}3837if (!success) {3838for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {3839if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(i), input_port_type)) {3840parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));3841break;3842}3843}3844}3845}38463847vsnode = Ref<VisualShaderNode>(vsn);3848} else {3849StringName base_type;3850bool is_native = add_options[p_idx].is_native;38513852if (is_native) {3853base_type = add_options[p_idx].type;3854} else {3855ERR_FAIL_COND(add_options[p_idx].script.is_null());3856base_type = add_options[p_idx].script->get_instance_base_type();3857}3858VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));3859ERR_FAIL_NULL(vsn);3860vsnode = Ref<VisualShaderNode>(vsn);3861if (!is_native) {3862vsnode->set_script(add_options[p_idx].script);3863}3864VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsn);3865ERR_FAIL_NULL(custom_node);3866custom_node->update_property_default_values();3867custom_node->update_input_port_default_values();3868custom_node->update_properties();3869}38703871bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr);3872bool is_texture3d = (Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr()) != nullptr);3873bool is_texture2d_array = (Object::cast_to<VisualShaderNodeTexture2DArray>(vsnode.ptr()) != nullptr);3874bool is_cubemap = (Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr()) != nullptr);3875bool is_curve = (Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr()) != nullptr);3876bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr);3877bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr);3878bool is_mesh_emitter = (Object::cast_to<VisualShaderNodeParticleMeshEmitter>(vsnode.ptr()) != nullptr);38793880Point2 position = graph->get_scroll_offset();38813882if (saved_node_pos_dirty) {3883position += saved_node_pos;3884} else {3885position += graph->get_size() * 0.5;3886position /= EDSCALE;3887}3888position /= graph->get_zoom();3889position /= cached_theme_base_scale;3890saved_node_pos_dirty = false;38913892int id_to_use = visual_shader->get_valid_node_id(type);38933894EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();3895if (p_resource_path.is_empty()) {3896undo_redo->create_action(TTR("Add Node to Visual Shader"));3897} else {3898id_to_use += p_node_idx;3899}3900undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, vsnode, position, id_to_use);3901undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_to_use);3902undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_to_use, false, true);3903undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_to_use, false);39043905VisualShaderNodeExpression *expr = Object::cast_to<VisualShaderNodeExpression>(vsnode.ptr());3906if (expr) {3907expr->set_size(Size2(250 * EDSCALE, 150 * EDSCALE));3908}39093910Ref<VisualShaderNodeFrame> frame = vsnode;3911if (frame.is_valid()) {3912frame->set_size(Size2(320 * EDSCALE, 180 * EDSCALE));3913}39143915Ref<VisualShaderNodeReroute> reroute = vsnode;39163917bool created_expression_port = false;39183919// A node is inserted in an already present connection.3920if (from_node != -1 && from_slot != -1 && to_node != -1 && to_slot != -1) {3921undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, to_node, to_slot);3922undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, to_node, to_slot);3923undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, to_node, to_slot);3924undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, to_node, to_slot);3925}39263927// Create a connection from the output port of an existing node to the new one.3928if (from_node != -1 && from_slot != -1) {3929VisualShaderNode::PortType output_port_type = visual_shader->get_node(type, from_node)->get_output_port_type(from_slot);39303931if (expr && expr->is_editable()) {3932expr->add_input_port(0, output_port_type, "input0");3933created_expression_port = true;3934}39353936if (vsnode->get_input_port_count() > 0 || created_expression_port) {3937int _to_node = id_to_use;39383939if (created_expression_port) {3940int _to_slot = 0;3941undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3942undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3943undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3944undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3945} else {3946int _to_slot = -1;39473948// Attempting to connect to the default input port or to the first correct port (if it's not found).3949for (int i = 0; i < vsnode->get_input_port_count(); i++) {3950if (visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(i)) || reroute.is_valid()) {3951if (i == vsnode->get_default_input_port(output_port_type)) {3952_to_slot = i;3953break;3954} else if (_to_slot == -1) {3955_to_slot = i;3956}3957}3958}39593960if (_to_slot >= 0) {3961undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3962undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3963undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);3964undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);3965}3966}39673968if (output_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {3969if (is_texture2d) {3970undo_redo->force_fixed_history(); // vsnode is freshly created and has no path, so history can't be correctly determined.3971undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeTexture::SOURCE_PORT);3972}3973if (is_texture3d || is_texture2d_array) {3974undo_redo->force_fixed_history();3975undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeSample3D::SOURCE_PORT);3976}3977if (is_cubemap) {3978undo_redo->force_fixed_history();3979undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeCubemap::SOURCE_PORT);3980}3981}3982}3983}39843985// Create a connection from the new node to an input port of an existing one.3986if (to_node != -1 && to_slot != -1) {3987VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);39883989if (expr && expr->is_editable() && input_port_type != VisualShaderNode::PORT_TYPE_SAMPLER) {3990expr->add_output_port(0, input_port_type, "output0");3991String initial_expression_code;39923993switch (input_port_type) {3994case VisualShaderNode::PORT_TYPE_SCALAR:3995initial_expression_code = "output0 = 1.0;";3996break;3997case VisualShaderNode::PORT_TYPE_SCALAR_INT:3998initial_expression_code = "output0 = 1;";3999break;4000case VisualShaderNode::PORT_TYPE_SCALAR_UINT:4001initial_expression_code = "output0 = 1u;";4002break;4003case VisualShaderNode::PORT_TYPE_VECTOR_2D:4004initial_expression_code = "output0 = vec2(1.0, 1.0);";4005break;4006case VisualShaderNode::PORT_TYPE_VECTOR_3D:4007initial_expression_code = "output0 = vec3(1.0, 1.0, 1.0);";4008break;4009case VisualShaderNode::PORT_TYPE_VECTOR_4D:4010initial_expression_code = "output0 = vec4(1.0, 1.0, 1.0, 1.0);";4011break;4012case VisualShaderNode::PORT_TYPE_BOOLEAN:4013initial_expression_code = "output0 = true;";4014break;4015case VisualShaderNode::PORT_TYPE_TRANSFORM:4016initial_expression_code = "output0 = mat4(1.0);";4017break;4018default:4019break;4020}40214022expr->set_expression(initial_expression_code);4023expr->set_size(Size2(500 * EDSCALE, 200 * EDSCALE));4024created_expression_port = true;4025}4026if (vsnode->get_output_port_count() > 0 || created_expression_port) {4027int _from_node = id_to_use;40284029if (created_expression_port) {4030int _from_slot = 0;4031undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);4032undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);4033undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);4034undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);4035} else {4036// Need to setting up Input node properly before committing since `is_port_types_compatible` (calling below) is using `mode` and `shader_type`.4037VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsnode.ptr());4038if (input) {4039input->set_shader_mode(visual_shader->get_mode());4040input->set_shader_type(get_current_shader_type());4041}40424043// Attempting to connect to the first correct port.4044for (int i = 0; i < vsnode->get_output_port_count(); i++) {4045if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type) || reroute.is_valid()) {4046undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);4047undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot);4048undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);4049undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot);4050break;4051}4052}4053}4054}4055}40564057_member_cancel();40584059if (is_parameter) {4060undo_redo->add_do_method(this, "_update_parameters", true);4061undo_redo->add_undo_method(this, "_update_parameters", true);4062}40634064if (is_curve) {4065callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve).call_deferred(id_to_use);4066}40674068if (is_curve_xyz) {4069callable_mp(graph_plugin.ptr(), &VisualShaderGraphPlugin::update_curve_xyz).call_deferred(id_to_use);4070}40714072if (p_resource_path.is_empty()) {4073undo_redo->commit_action();4074} else {4075//post-initialization40764077if (is_texture2d || is_texture3d || is_curve || is_curve_xyz) {4078undo_redo->force_fixed_history();4079undo_redo->add_do_method(vsnode.ptr(), "set_texture", ResourceLoader::load(p_resource_path));4080return;4081}40824083if (is_cubemap) {4084undo_redo->force_fixed_history();4085undo_redo->add_do_method(vsnode.ptr(), "set_cube_map", ResourceLoader::load(p_resource_path));4086return;4087}40884089if (is_texture2d_array) {4090undo_redo->force_fixed_history();4091undo_redo->add_do_method(vsnode.ptr(), "set_texture_array", ResourceLoader::load(p_resource_path));4092return;4093}40944095if (is_mesh_emitter) {4096undo_redo->add_do_method(vsnode.ptr(), "set_mesh", ResourceLoader::load(p_resource_path));4097return;4098}4099}4100}41014102void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) {4103EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4104undo_redo->create_action(vformat(TTR("Add Varying to Visual Shader: %s"), p_name));41054106undo_redo->add_do_method(visual_shader.ptr(), "add_varying", p_name, p_mode, p_type);4107undo_redo->add_undo_method(visual_shader.ptr(), "remove_varying", p_name);41084109undo_redo->add_do_method(this, "_update_varyings");4110undo_redo->add_undo_method(this, "_update_varyings");41114112for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {4113if (p_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {4114continue;4115}41164117VisualShader::Type type = VisualShader::Type(i);4118Vector<int> nodes = visual_shader->get_node_list(type);41194120for (int j = 0; j < nodes.size(); j++) {4121int node_id = nodes[j];4122Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);4123Ref<VisualShaderNodeVarying> var = vsnode;41244125if (var.is_valid()) {4126undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);4127undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);4128}4129}4130}41314132undo_redo->add_do_method(this, "_update_varying_tree");4133undo_redo->add_undo_method(this, "_update_varying_tree");4134undo_redo->commit_action();4135}41364137void VisualShaderEditor::_remove_varying(const String &p_name) {4138EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4139undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name));41404141VisualShader::VaryingMode var_mode = visual_shader->get_varying_mode(p_name);41424143undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", p_name);4144undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", p_name, var_mode, visual_shader->get_varying_type(p_name));41454146undo_redo->add_do_method(this, "_update_varyings");4147undo_redo->add_undo_method(this, "_update_varyings");41484149for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {4150if (var_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {4151continue;4152}41534154VisualShader::Type type = VisualShader::Type(i);4155Vector<int> nodes = visual_shader->get_node_list(type);41564157for (int j = 0; j < nodes.size(); j++) {4158int node_id = nodes[j];4159Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);4160Ref<VisualShaderNodeVarying> var = vsnode;41614162if (var.is_valid()) {4163String var_name = var->get_varying_name();41644165if (var_name == p_name) {4166undo_redo->add_do_method(var.ptr(), "set_varying_name", "[None]");4167undo_redo->add_undo_method(var.ptr(), "set_varying_name", var_name);4168undo_redo->add_do_method(var.ptr(), "set_varying_type", VisualShader::VARYING_TYPE_FLOAT);4169undo_redo->add_undo_method(var.ptr(), "set_varying_type", var->get_varying_type());4170}4171undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);4172undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);4173}4174}41754176List<VisualShader::Connection> node_connections;4177visual_shader->get_node_connections(type, &node_connections);41784179for (VisualShader::Connection &E : node_connections) {4180Ref<VisualShaderNodeVaryingGetter> var_getter = Object::cast_to<VisualShaderNodeVaryingGetter>(visual_shader->get_node(type, E.from_node).ptr());4181if (var_getter.is_valid() && E.from_port > 0) {4182undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4183undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4184undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4185undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4186}4187Ref<VisualShaderNodeVaryingSetter> var_setter = Object::cast_to<VisualShaderNodeVaryingSetter>(visual_shader->get_node(type, E.to_node).ptr());4188if (var_setter.is_valid() && E.to_port > 0) {4189undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4190undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4191undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4192undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4193}4194}4195}41964197undo_redo->add_do_method(this, "_update_varying_tree");4198undo_redo->add_undo_method(this, "_update_varying_tree");4199undo_redo->commit_action();4200}42014202void VisualShaderEditor::_update_varyings() {4203VisualShaderNodeVarying::clear_varyings(visual_shader->get_rid());42044205for (int i = 0; i < visual_shader->get_varyings_count(); i++) {4206const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);42074208if (var != nullptr) {4209VisualShaderNodeVarying::add_varying(visual_shader->get_rid(), var->name, var->mode, var->type);4210}4211}4212}42134214void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node) {4215VisualShader::Type type = get_current_shader_type();4216drag_buffer.push_back({ type, p_node, p_from / cached_theme_base_scale, p_to / cached_theme_base_scale });4217if (!drag_dirty) {4218callable_mp(this, &VisualShaderEditor::_nodes_dragged).call_deferred();4219}4220drag_dirty = true;4221}42224223void VisualShaderEditor::_nodes_dragged() {4224drag_dirty = false;42254226EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4227if (frame_node_id_to_link_to == -1) {4228undo_redo->create_action(TTR("Move VisualShader Node(s)"));4229} else {4230undo_redo->create_action(TTR("Move and Attach VisualShader Node(s) to parent frame"));4231}42324233for (const DragOp &E : drag_buffer) {4234undo_redo->add_do_method(visual_shader.ptr(), "set_node_position", E.type, E.node, E.to);4235undo_redo->add_undo_method(visual_shader.ptr(), "set_node_position", E.type, E.node, E.from);4236undo_redo->add_do_method(graph_plugin.ptr(), "set_node_position", E.type, E.node, E.to);4237undo_redo->add_undo_method(graph_plugin.ptr(), "set_node_position", E.type, E.node, E.from);4238}42394240for (const int node_id : nodes_link_to_frame_buffer) {4241VisualShader::Type type = get_current_shader_type();4242Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, node_id);42434244undo_redo->add_do_method(visual_shader.ptr(), "attach_node_to_frame", type, node_id, frame_node_id_to_link_to);4245undo_redo->add_do_method(graph_plugin.ptr(), "attach_node_to_frame", type, node_id, frame_node_id_to_link_to);4246undo_redo->add_undo_method(graph_plugin.ptr(), "detach_node_from_frame", type, node_id);4247undo_redo->add_undo_method(visual_shader.ptr(), "detach_node_from_frame", type, node_id);4248}42494250undo_redo->commit_action();42514252_handle_node_drop_on_connection();42534254drag_buffer.clear();4255nodes_link_to_frame_buffer.clear();4256frame_node_id_to_link_to = -1;4257}42584259void VisualShaderEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {4260VisualShader::Type type = get_current_shader_type();42614262int from = p_from.to_int();4263int to = p_to.to_int();4264bool swap = last_to_node != -1 && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);42654266if (!visual_shader->can_connect_nodes(type, from, p_from_index, to, p_to_index)) {4267return;4268}42694270EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4271undo_redo->create_action(TTR("Nodes Connected"));42724273List<VisualShader::Connection> conns;4274visual_shader->get_node_connections(type, &conns);42754276for (const VisualShader::Connection &E : conns) {4277if (E.to_node == to && E.to_port == p_to_index) {4278undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4279undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4280undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4281undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);42824283if (swap) {4284undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4285undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4286undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4287undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);4288}4289break;4290}4291}42924293undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4294undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);4295undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4296undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);42974298undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, from);4299undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, from);4300undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);4301undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);4302undo_redo->commit_action();43034304last_to_node = -1;4305last_to_port = -1;4306}43074308void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {4309graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);43104311VisualShader::Type type = get_current_shader_type();43124313int from = p_from.to_int();4314int to = p_to.to_int();43154316last_to_node = to;4317last_to_port = p_to_index;43184319info_label->show();43204321EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4322undo_redo->create_action(TTR("Nodes Disconnected"));4323undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);4324undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4325undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);4326undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);4327undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);4328undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);4329undo_redo->commit_action();4330}43314332void VisualShaderEditor::_connection_drag_ended() {4333info_label->hide();4334}43354336void VisualShaderEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {4337from_node = p_from.to_int();4338from_slot = p_from_slot;4339VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;4340VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;4341Ref<VisualShaderNode> node = visual_shader->get_node(get_current_shader_type(), from_node);4342if (node.is_valid()) {4343output_port_type = node->get_output_port_type(from_slot);4344}4345_show_members_dialog(true, input_port_type, output_port_type);4346}43474348void VisualShaderEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {4349to_node = p_to.to_int();4350to_slot = p_to_slot;4351VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;4352VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;4353Ref<VisualShaderNode> node = visual_shader->get_node(get_current_shader_type(), to_node);4354if (node.is_valid()) {4355input_port_type = node->get_input_port_type(to_slot);4356}4357_show_members_dialog(true, input_port_type, output_port_type);4358}43594360bool VisualShaderEditor::_check_node_drop_on_connection(const Vector2 &p_position, Ref<GraphEdit::Connection> *r_closest_connection, int *r_from_port, int *r_to_port) {4361VisualShader::Type shader_type = get_current_shader_type();43624363// Get selected graph node.4364Ref<VisualShaderNode> selected_vsnode;4365int selected_node_id = -1;4366int selected_node_count = 0;4367Rect2 selected_node_rect;43684369for (int i = 0; i < graph->get_child_count(); i++) {4370GraphNode *graph_node = Object::cast_to<GraphNode>(graph->get_child(i));4371if (graph_node && graph_node->is_selected()) {4372selected_node_id = String(graph_node->get_name()).to_int();4373Ref<VisualShaderNode> vsnode = visual_shader->get_node(shader_type, selected_node_id);4374if (!vsnode->is_deletable()) {4375continue;4376}43774378selected_node_count += 1;43794380Ref<VisualShaderNode> node = visual_shader->get_node(shader_type, selected_node_id);4381selected_vsnode = node;4382selected_node_rect = graph_node->get_rect();4383}4384}43854386// Only a single node - which has both input and output ports but is not connected yet - can be inserted.4387if (selected_node_count != 1 || selected_vsnode.is_null()) {4388return false;4389}43904391// Check whether the dragged node was dropped over a connection.4392List<Ref<GraphEdit::Connection>> intersecting_connections = graph->get_connections_intersecting_with_rect(selected_node_rect);43934394if (intersecting_connections.is_empty()) {4395return false;4396}43974398Ref<GraphEdit::Connection> intersecting_connection = intersecting_connections.front()->get();43994400if (selected_vsnode->is_any_port_connected() || selected_vsnode->get_input_port_count() == 0 || selected_vsnode->get_output_port_count() == 0) {4401return false;4402}44034404VisualShaderNode::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);4405VisualShaderNode::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);44064407Ref<VisualShaderNodeReroute> reroute_node = selected_vsnode;44084409// Searching for the default port or the first compatible input port of the node to insert.4410int _to_port = -1;4411for (int i = 0; i < selected_vsnode->get_input_port_count(); i++) {4412if (visual_shader->is_port_types_compatible(original_port_type_from, selected_vsnode->get_input_port_type(i)) || reroute_node.is_valid()) {4413if (i == selected_vsnode->get_default_input_port(original_port_type_from)) {4414_to_port = i;4415break;4416} else if (_to_port == -1) {4417_to_port = i;4418}4419}4420}44214422// Searching for the first compatible output port of the node to insert.4423int _from_port = -1;4424for (int i = 0; i < selected_vsnode->get_output_port_count(); i++) {4425if (visual_shader->is_port_types_compatible(selected_vsnode->get_output_port_type(i), original_port_type_to) || reroute_node.is_valid()) {4426_from_port = i;4427break;4428}4429}44304431if (_to_port == -1 || _from_port == -1) {4432return false;4433}44344435if (r_closest_connection != nullptr) {4436*r_closest_connection = intersecting_connection;4437}4438if (r_from_port != nullptr) {4439*r_from_port = _from_port;4440}4441if (r_to_port != nullptr) {4442*r_to_port = _to_port;4443}44444445return true;4446}44474448void VisualShaderEditor::_handle_node_drop_on_connection() {4449EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4450undo_redo->create_action(TTR("Insert node"));44514452// Check whether the dragged node was dropped over a connection.4453Ref<GraphEdit::Connection> closest_connection;4454int _from_port = -1;4455int _to_port = -1;44564457if (!_check_node_drop_on_connection(graph->get_local_mouse_position(), &closest_connection, &_from_port, &_to_port)) {4458return;4459}44604461int selected_node_id = drag_buffer.front()->get().node;4462VisualShader::Type shader_type = get_current_shader_type();4463Ref<VisualShaderNode> selected_vsnode = visual_shader->get_node(shader_type, selected_node_id);44644465// Delete the old connection.4466undo_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);4467undo_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);4468undo_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);4469undo_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);44704471// Add the connection to the dropped node.4472undo_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);4473undo_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);4474undo_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);4475undo_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);44764477// Add the connection from the dropped node.4478undo_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);4479undo_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);4480undo_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);4481undo_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);44824483undo_redo->commit_action();44844485call_deferred(SNAME("_update_graph"));4486}44874488void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {4489VisualShader::Type type = VisualShader::Type(p_type);4490List<VisualShader::Connection> conns;4491visual_shader->get_node_connections(type, &conns);44924493EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4494for (const int &F : p_nodes) {4495for (const VisualShader::Connection &E : conns) {4496if (E.from_node == F || E.to_node == F) {4497undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4498}4499}4500}45014502// The VS nodes need to be added before attaching them to frames.4503for (const int &F : p_nodes) {4504Ref<VisualShaderNode> node = visual_shader->get_node(type, F);4505undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, F), F);4506undo_redo->add_undo_method(graph_plugin.ptr(), "add_node", type, F, false, false);4507}45084509// Update frame references.4510for (const int &node_id : p_nodes) {4511Ref<VisualShaderNodeFrame> frame = visual_shader->get_node(type, node_id);4512if (frame.is_valid()) {4513for (const int &attached_node_id : frame->get_attached_nodes()) {4514undo_redo->add_do_method(visual_shader.ptr(), "detach_node_from_frame", type, attached_node_id);4515undo_redo->add_do_method(graph_plugin.ptr(), "detach_node_from_frame", type, attached_node_id);4516undo_redo->add_undo_method(visual_shader.ptr(), "attach_node_to_frame", type, attached_node_id, node_id);4517undo_redo->add_undo_method(graph_plugin.ptr(), "attach_node_to_frame", type, attached_node_id, node_id);4518}4519}45204521Ref<VisualShaderNode> node = visual_shader->get_node(type, node_id);4522if (node->get_frame() == -1) {4523continue;4524}45254526undo_redo->add_do_method(visual_shader.ptr(), "detach_node_from_frame", type, node_id);4527undo_redo->add_do_method(graph_plugin.ptr(), "detach_node_from_frame", type, node_id);4528undo_redo->add_undo_method(visual_shader.ptr(), "attach_node_to_frame", type, node_id, node->get_frame());4529undo_redo->add_undo_method(graph_plugin.ptr(), "attach_node_to_frame", type, node_id, node->get_frame());4530}45314532// Restore size of the frame nodes.4533for (const int &F : p_nodes) {4534Ref<VisualShaderNodeFrame> frame = visual_shader->get_node(type, F);4535if (frame.is_valid()) {4536undo_redo->add_undo_method(this, "_set_node_size", type, F, frame->get_size());4537}4538}45394540HashSet<String> parameter_names;45414542for (const int &F : p_nodes) {4543Ref<VisualShaderNode> node = visual_shader->get_node(type, F);45444545undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F);45464547VisualShaderNodeParameter *parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());4548if (parameter) {4549parameter_names.insert(parameter->get_parameter_name());4550}4551}45524553List<VisualShader::Connection> used_conns;4554for (const int &F : p_nodes) {4555for (const VisualShader::Connection &E : conns) {4556if (E.from_node == F || E.to_node == F) {4557bool cancel = false;4558for (const VisualShader::Connection &R : used_conns) {4559if (R.from_node == E.from_node && R.from_port == E.from_port && R.to_node == E.to_node && R.to_port == E.to_port) {4560cancel = true; // to avoid ERR_ALREADY_EXISTS warning4561break;4562}4563}4564if (!cancel) {4565undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4566undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);4567used_conns.push_back(E);4568}4569}4570}4571}45724573// Delete nodes from the graph.4574for (const int &F : p_nodes) {4575undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F, false);4576}45774578// Update parameter refs if any parameter has been deleted.4579if (parameter_names.size() > 0) {4580undo_redo->add_do_method(this, "_update_parameters", true);4581undo_redo->add_undo_method(this, "_update_parameters", true);45824583_update_parameter_refs(parameter_names);4584}4585}45864587void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to) {4588EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4589undo_redo->add_do_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_to);4590undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from);4591}45924593void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port) {4594Ref<VisualShaderNode> node = visual_shader->get_node(p_type_id, p_node_id);4595ERR_FAIL_COND(node.is_null());4596ERR_FAIL_COND(!node->has_method("set_constant"));4597node->call("set_constant", p_var);4598if (p_preview_port != -1) {4599node->set_output_port_for_preview(p_preview_port);4600}4601}46024603void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port) {4604Ref<VisualShaderNodeParameter> parameter = visual_shader->get_node(p_type_id, p_node_id);4605ERR_FAIL_COND(parameter.is_null());46064607String valid_name = visual_shader->validate_parameter_name(parameter->get_parameter_name(), parameter);4608parameter->set_parameter_name(valid_name);4609graph_plugin->set_parameter_name(p_type_id, p_node_id, valid_name);46104611if (parameter->has_method("set_default_value_enabled")) {4612parameter->call("set_default_value_enabled", true);4613parameter->call("set_default_value", p_var);4614}4615if (p_preview_port != -1) {4616parameter->set_output_port_for_preview(p_preview_port);4617}4618}46194620void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {4621VisualShader::Type type_id = get_current_shader_type();46224623EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4624if (!p_vice_versa) {4625undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));4626} else {4627undo_redo->create_action(TTR("Convert Parameter Node(s) To Constant(s)"));4628}46294630const HashSet<int> ¤t_set = p_vice_versa ? selected_parameters : selected_constants;4631HashSet<String> deleted_names;46324633for (const int &E : current_set) {4634int node_id = E;4635Ref<VisualShaderNode> node = visual_shader->get_node(type_id, node_id);4636bool caught = false;4637Variant var;46384639// float4640if (!p_vice_versa) {4641Ref<VisualShaderNodeFloatConstant> float_const = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());4642if (float_const.is_valid()) {4643_replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatParameter");4644var = float_const->get_constant();4645caught = true;4646}4647} else {4648Ref<VisualShaderNodeFloatParameter> float_parameter = Object::cast_to<VisualShaderNodeFloatParameter>(node.ptr());4649if (float_parameter.is_valid()) {4650_replace_node(type_id, node_id, "VisualShaderNodeFloatParameter", "VisualShaderNodeFloatConstant");4651var = float_parameter->get_default_value();4652caught = true;4653}4654}46554656// int4657if (!caught) {4658if (!p_vice_versa) {4659Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());4660if (int_const.is_valid()) {4661_replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntParameter");4662var = int_const->get_constant();4663caught = true;4664}4665} else {4666Ref<VisualShaderNodeIntParameter> int_parameter = Object::cast_to<VisualShaderNodeIntParameter>(node.ptr());4667if (int_parameter.is_valid()) {4668_replace_node(type_id, node_id, "VisualShaderNodeIntParameter", "VisualShaderNodeIntConstant");4669var = int_parameter->get_default_value();4670caught = true;4671}4672}4673}46744675// boolean4676if (!caught) {4677if (!p_vice_versa) {4678Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());4679if (boolean_const.is_valid()) {4680_replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanParameter");4681var = boolean_const->get_constant();4682caught = true;4683}4684} else {4685Ref<VisualShaderNodeBooleanParameter> boolean_parameter = Object::cast_to<VisualShaderNodeBooleanParameter>(node.ptr());4686if (boolean_parameter.is_valid()) {4687_replace_node(type_id, node_id, "VisualShaderNodeBooleanParameter", "VisualShaderNodeBooleanConstant");4688var = boolean_parameter->get_default_value();4689caught = true;4690}4691}4692}46934694// vec24695if (!caught) {4696if (!p_vice_versa) {4697Ref<VisualShaderNodeVec2Constant> vec2_const = Object::cast_to<VisualShaderNodeVec2Constant>(node.ptr());4698if (vec2_const.is_valid()) {4699_replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Parameter");4700var = vec2_const->get_constant();4701caught = true;4702}4703} else {4704Ref<VisualShaderNodeVec2Parameter> vec2_parameter = Object::cast_to<VisualShaderNodeVec2Parameter>(node.ptr());4705if (vec2_parameter.is_valid()) {4706_replace_node(type_id, node_id, "VisualShaderNodeVec2Parameter", "VisualShaderNodeVec2Constant");4707var = vec2_parameter->get_default_value();4708caught = true;4709}4710}4711}47124713// vec34714if (!caught) {4715if (!p_vice_versa) {4716Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());4717if (vec3_const.is_valid()) {4718_replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Parameter");4719var = vec3_const->get_constant();4720caught = true;4721}4722} else {4723Ref<VisualShaderNodeVec3Parameter> vec3_parameter = Object::cast_to<VisualShaderNodeVec3Parameter>(node.ptr());4724if (vec3_parameter.is_valid()) {4725_replace_node(type_id, node_id, "VisualShaderNodeVec3Parameter", "VisualShaderNodeVec3Constant");4726var = vec3_parameter->get_default_value();4727caught = true;4728}4729}4730}47314732// vec44733if (!caught) {4734if (!p_vice_versa) {4735Ref<VisualShaderNodeVec4Constant> vec4_const = Object::cast_to<VisualShaderNodeVec4Constant>(node.ptr());4736if (vec4_const.is_valid()) {4737_replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Parameter");4738var = vec4_const->get_constant();4739caught = true;4740}4741} else {4742Ref<VisualShaderNodeVec4Parameter> vec4_parameter = Object::cast_to<VisualShaderNodeVec4Parameter>(node.ptr());4743if (vec4_parameter.is_valid()) {4744_replace_node(type_id, node_id, "VisualShaderNodeVec4Parameter", "VisualShaderNodeVec4Constant");4745var = vec4_parameter->get_default_value();4746caught = true;4747}4748}4749}47504751// color4752if (!caught) {4753if (!p_vice_versa) {4754Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());4755if (color_const.is_valid()) {4756_replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorParameter");4757var = color_const->get_constant();4758caught = true;4759}4760} else {4761Ref<VisualShaderNodeColorParameter> color_parameter = Object::cast_to<VisualShaderNodeColorParameter>(node.ptr());4762if (color_parameter.is_valid()) {4763_replace_node(type_id, node_id, "VisualShaderNodeColorParameter", "VisualShaderNodeColorConstant");4764var = color_parameter->get_default_value();4765caught = true;4766}4767}4768}47694770// transform4771if (!caught) {4772if (!p_vice_versa) {4773Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());4774if (transform_const.is_valid()) {4775_replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformParameter");4776var = transform_const->get_constant();4777caught = true;4778}4779} else {4780Ref<VisualShaderNodeTransformParameter> transform_parameter = Object::cast_to<VisualShaderNodeTransformParameter>(node.ptr());4781if (transform_parameter.is_valid()) {4782_replace_node(type_id, node_id, "VisualShaderNodeTransformParameter", "VisualShaderNodeTransformConstant");4783var = transform_parameter->get_default_value();4784caught = true;4785}4786}4787}4788ERR_CONTINUE(!caught);4789int preview_port = node->get_output_port_for_preview();47904791if (!p_vice_versa) {4792undo_redo->add_do_method(this, "_update_parameter", type_id, node_id, var, preview_port);4793undo_redo->add_undo_method(this, "_update_constant", type_id, node_id, var, preview_port);4794} else {4795undo_redo->add_do_method(this, "_update_constant", type_id, node_id, var, preview_port);4796undo_redo->add_undo_method(this, "_update_parameter", type_id, node_id, var, preview_port);47974798Ref<VisualShaderNodeParameter> parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());4799ERR_CONTINUE(parameter.is_null());48004801deleted_names.insert(parameter->get_parameter_name());4802}48034804undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, node_id);4805undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, node_id);4806}48074808undo_redo->add_do_method(this, "_update_parameters", true);4809undo_redo->add_undo_method(this, "_update_parameters", true);48104811if (deleted_names.size() > 0) {4812_update_parameter_refs(deleted_names);4813}48144815undo_redo->commit_action();4816}48174818void VisualShaderEditor::_detach_nodes_from_frame(int p_type, const List<int> &p_nodes) {4819EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4820for (int node_id : p_nodes) {4821Ref<VisualShaderNode> node = visual_shader->get_node((VisualShader::Type)p_type, node_id);4822if (node.is_null()) {4823continue;4824}4825int frame_id = node->get_frame();4826if (frame_id != -1) {4827undo_redo->add_do_method(graph_plugin.ptr(), "detach_node_from_frame", p_type, node_id);4828undo_redo->add_do_method(visual_shader.ptr(), "detach_node_from_frame", p_type, node_id);4829undo_redo->add_undo_method(visual_shader.ptr(), "attach_node_to_frame", p_type, node_id, frame_id);4830undo_redo->add_undo_method(graph_plugin.ptr(), "attach_node_to_frame", p_type, node_id, frame_id);4831}4832}4833}48344835void VisualShaderEditor::_detach_nodes_from_frame_request() {4836// Called from context menu.4837List<int> to_detach_node_ids;4838for (int i = 0; i < graph->get_child_count(); i++) {4839GraphElement *gn = Object::cast_to<GraphElement>(graph->get_child(i));4840if (gn) {4841int id = String(gn->get_name()).to_int();4842if (gn->is_selected()) {4843to_detach_node_ids.push_back(id);4844}4845}4846}4847if (to_detach_node_ids.is_empty()) {4848return;4849}48504851EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4852undo_redo->create_action(TTR("Detach VisualShader Node(s) from Frame"));4853_detach_nodes_from_frame(get_current_shader_type(), to_detach_node_ids);4854undo_redo->commit_action();4855}48564857void VisualShaderEditor::_delete_node_request(int p_type, int p_node) {4858Ref<VisualShaderNode> node = visual_shader->get_node((VisualShader::Type)p_type, p_node);4859if (!node->is_deletable()) {4860return;4861}48624863List<int> to_erase;4864to_erase.push_back(p_node);48654866EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4867undo_redo->create_action(TTR("Delete VisualShader Node"));4868_delete_nodes(p_type, to_erase);4869undo_redo->commit_action();4870}48714872void VisualShaderEditor::_delete_nodes_request(const TypedArray<StringName> &p_nodes) {4873List<int> to_erase;48744875if (p_nodes.is_empty()) {4876// Called from context menu.4877for (int i = 0; i < graph->get_child_count(); i++) {4878GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));4879if (!graph_element) {4880continue;4881}48824883VisualShader::Type type = get_current_shader_type();4884int id = String(graph_element->get_name()).to_int();4885Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);4886if (vsnode->is_deletable() && graph_element->is_selected()) {4887to_erase.push_back(graph_element->get_name().operator String().to_int());4888}4889}4890} else {4891VisualShader::Type type = get_current_shader_type();4892for (int i = 0; i < p_nodes.size(); i++) {4893int id = p_nodes[i].operator String().to_int();4894Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);4895if (vsnode->is_deletable()) {4896to_erase.push_back(id);4897}4898}4899}49004901if (to_erase.is_empty()) {4902return;4903}49044905EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();4906undo_redo->create_action(TTR("Delete VisualShader Node(s)"));4907_delete_nodes(get_current_shader_type(), to_erase);4908undo_redo->commit_action();4909}49104911void VisualShaderEditor::_node_selected(Object *p_node) {4912VisualShader::Type type = get_current_shader_type();49134914GraphElement *graph_element = Object::cast_to<GraphElement>(p_node);4915ERR_FAIL_NULL(graph_element);49164917int id = String(graph_element->get_name()).to_int();49184919Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);4920ERR_FAIL_COND(vsnode.is_null());4921}49224923void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {4924Ref<InputEventMouseMotion> mm = p_event;4925Ref<InputEventMouseButton> mb = p_event;4926VisualShader::Type type = get_current_shader_type();49274928// Highlight valid connection on which a node can be dropped.4929if (mm.is_valid() && mm->get_button_mask().has_flag(MouseButtonMask::LEFT)) {4930Ref<GraphEdit::Connection> closest_connection;4931graph->reset_all_connection_activity();4932if (_check_node_drop_on_connection(graph->get_local_mouse_position(), &closest_connection)) {4933graph->set_connection_activity(closest_connection->from_node, closest_connection->from_port, closest_connection->to_node, closest_connection->to_port, 1.0);4934}4935}49364937Ref<VisualShaderNode> selected_vsnode;4938// Right click actions.4939if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {4940selected_constants.clear();4941selected_parameters.clear();4942selected_frame = -1;4943selected_float_constant = -1;49444945List<int> selected_deletable_graph_elements;4946List<GraphElement *> selected_graph_elements;4947for (int i = 0; i < graph->get_child_count(); i++) {4948GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));4949if (!graph_element) {4950continue;4951}4952int id = String(graph_element->get_name()).to_int();4953Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);49544955if (!graph_element->is_selected()) {4956continue;4957}49584959selected_graph_elements.push_back(graph_element);49604961if (!vsnode->is_deletable()) {4962continue;4963}49644965selected_deletable_graph_elements.push_back(id);49664967Ref<VisualShaderNode> node = visual_shader->get_node(type, id);4968selected_vsnode = node;49694970VisualShaderNodeFrame *frame_node = Object::cast_to<VisualShaderNodeFrame>(node.ptr());4971if (frame_node != nullptr) {4972selected_frame = id;4973}4974VisualShaderNodeConstant *constant_node = Object::cast_to<VisualShaderNodeConstant>(node.ptr());4975if (constant_node != nullptr) {4976selected_constants.insert(id);4977}4978VisualShaderNodeFloatConstant *float_constant_node = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());4979if (float_constant_node != nullptr) {4980selected_float_constant = id;4981}4982VisualShaderNodeParameter *parameter_node = Object::cast_to<VisualShaderNodeParameter>(node.ptr());4983if (parameter_node != nullptr && parameter_node->is_convertible_to_constant()) {4984selected_parameters.insert(id);4985}4986}49874988if (selected_deletable_graph_elements.size() > 1) {4989selected_frame = -1;4990selected_float_constant = -1;4991}49924993bool copy_buffer_empty = true;4994for (const CopyItem &item : copy_items_buffer) {4995if (!item.disabled) {4996copy_buffer_empty = false;4997break;4998}4999}50005001menu_point = graph->get_local_mouse_position();5002Point2 gpos = get_screen_position() + get_local_mouse_position();50035004Ref<GraphEdit::Connection> closest_connection = graph->get_closest_connection_at_point(menu_point);5005if (closest_connection.is_valid()) {5006clicked_connection = closest_connection;5007saved_node_pos = graph->get_local_mouse_position();5008saved_node_pos_dirty = true;5009connection_popup_menu->set_position(gpos);5010connection_popup_menu->reset_size();5011connection_popup_menu->popup();5012} else if (selected_graph_elements.is_empty() && copy_buffer_empty) {5013_show_members_dialog(true);5014} else {5015popup_menu->set_item_disabled(NodeMenuOptions::CUT, selected_deletable_graph_elements.is_empty());5016popup_menu->set_item_disabled(NodeMenuOptions::COPY, selected_deletable_graph_elements.is_empty());5017popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_buffer_empty);5018popup_menu->set_item_disabled(NodeMenuOptions::DELETE_, selected_deletable_graph_elements.is_empty());5019popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, selected_deletable_graph_elements.is_empty());5020popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_buffer_empty);50215022int temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR2);5023if (temp != -1) {5024popup_menu->remove_item(temp);5025}5026temp = popup_menu->get_item_index(NodeMenuOptions::FLOAT_CONSTANTS);5027if (temp != -1) {5028popup_menu->remove_item(temp);5029}5030temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);5031if (temp != -1) {5032popup_menu->remove_item(temp);5033}5034temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);5035if (temp != -1) {5036popup_menu->remove_item(temp);5037}5038temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR3);5039if (temp != -1) {5040popup_menu->remove_item(temp);5041}5042temp = popup_menu->get_item_index(NodeMenuOptions::UNLINK_FROM_PARENT_FRAME);5043if (temp != -1) {5044popup_menu->remove_item(temp);5045}5046temp = popup_menu->get_item_index(NodeMenuOptions::SET_FRAME_TITLE);5047if (temp != -1) {5048popup_menu->remove_item(temp);5049}5050temp = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_COLOR);5051if (temp != -1) {5052popup_menu->remove_item(temp);5053}5054temp = popup_menu->get_item_index(NodeMenuOptions::SET_FRAME_COLOR);5055if (temp != -1) {5056popup_menu->remove_item(temp);5057}5058temp = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);5059if (temp != -1) {5060popup_menu->remove_item(temp);5061}50625063if (selected_constants.size() > 0 || selected_parameters.size() > 0) {5064popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);50655066if (selected_float_constant != -1) {5067if (!constants_submenu) {5068constants_submenu = memnew(PopupMenu);50695070for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {5071constants_submenu->add_item(float_constant_defs[i].name, i);5072}5073constants_submenu->connect("index_pressed", callable_mp(this, &VisualShaderEditor::_float_constant_selected));5074}5075popup_menu->add_submenu_node_item(TTR("Float Constants"), constants_submenu, int(NodeMenuOptions::FLOAT_CONSTANTS));5076}50775078if (selected_constants.size() > 0) {5079popup_menu->add_item(TTR("Convert Constant(s) to Parameter(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);5080}50815082if (selected_parameters.size() > 0) {5083popup_menu->add_item(TTR("Convert Parameter(s) to Constant(s)"), NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);5084}5085}50865087// Check if any selected node is attached to a frame.5088bool is_attached_to_frame = false;5089for (GraphElement *graph_element : selected_graph_elements) {5090if (graph->get_element_frame(graph_element->get_name())) {5091is_attached_to_frame = true;5092break;5093}5094}50955096if (is_attached_to_frame) {5097popup_menu->add_item(TTR("Detach from Parent Frame"), NodeMenuOptions::UNLINK_FROM_PARENT_FRAME);5098}50995100if (selected_frame != -1) {5101popup_menu->add_separator("", NodeMenuOptions::SEPARATOR3);5102popup_menu->add_item(TTR("Set Frame Title"), NodeMenuOptions::SET_FRAME_TITLE);5103popup_menu->add_check_item(TTR("Enable Auto Shrink"), NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);5104popup_menu->add_check_item(TTR("Enable Tint Color"), NodeMenuOptions::ENABLE_FRAME_COLOR);51055106VisualShaderNodeFrame *frame_ref = Object::cast_to<VisualShaderNodeFrame>(selected_vsnode.ptr());5107if (frame_ref) {5108int item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_COLOR);5109popup_menu->set_item_checked(item_index, frame_ref->is_tint_color_enabled());5110if (frame_ref->is_tint_color_enabled()) {5111popup_menu->add_item(TTR("Set Tint Color"), NodeMenuOptions::SET_FRAME_COLOR);5112}51135114item_index = popup_menu->get_item_index(NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK);5115popup_menu->set_item_checked(item_index, frame_ref->is_autoshrink_enabled());5116}5117}51185119popup_menu->set_position(gpos);5120popup_menu->reset_size();5121popup_menu->popup();5122}5123}5124}51255126void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNode::PortType p_input_port_type, VisualShaderNode::PortType p_output_port_type) {5127if (members_input_port_type != p_input_port_type || members_output_port_type != p_output_port_type) {5128members_input_port_type = p_input_port_type;5129members_output_port_type = p_output_port_type;5130_update_options_menu();5131}51325133if (at_mouse_pos) {5134saved_node_pos_dirty = true;5135saved_node_pos = graph->get_local_mouse_position();51365137Point2 gpos = get_screen_position() + get_local_mouse_position();5138members_dialog->set_position(gpos);5139} else {5140saved_node_pos_dirty = false;5141members_dialog->set_position(graph->get_screen_position() + Point2(5 * EDSCALE, 65 * EDSCALE));5142}51435144if (members_dialog->is_visible()) {5145members_dialog->grab_focus();5146return;5147}51485149members_dialog->popup();51505151// Keep dialog within window bounds.5152Rect2 window_rect = Rect2(get_window()->get_position(), get_window()->get_size());5153Rect2 dialog_rect = Rect2(members_dialog->get_position(), members_dialog->get_size());5154Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).maxf(0);5155members_dialog->set_position(members_dialog->get_position() - difference);51565157node_filter->grab_focus();5158node_filter->select_all();5159}51605161void VisualShaderEditor::_varying_menu_id_pressed(int p_idx) {5162switch (VaryingMenuOptions(p_idx)) {5163case VaryingMenuOptions::ADD: {5164_show_add_varying_dialog();5165} break;5166case VaryingMenuOptions::REMOVE: {5167_show_remove_varying_dialog();5168} break;5169default:5170break;5171}5172}51735174void VisualShaderEditor::_show_add_varying_dialog() {5175_varying_name_changed(varying_name->get_text());51765177add_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));5178add_varying_dialog->popup();51795180varying_name->grab_focus();51815182// Keep dialog within window bounds.5183Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());5184Rect2 dialog_rect = Rect2(add_varying_dialog->get_position(), add_varying_dialog->get_size());5185Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).maxf(0);5186add_varying_dialog->set_position(add_varying_dialog->get_position() - difference);5187}51885189void VisualShaderEditor::_show_remove_varying_dialog() {5190remove_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));5191remove_varying_dialog->popup();51925193varyings->grab_focus();51945195// Keep dialog within window bounds.5196Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());5197Rect2 dialog_rect = Rect2(remove_varying_dialog->get_position(), remove_varying_dialog->get_size());5198Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).maxf(0);5199remove_varying_dialog->set_position(remove_varying_dialog->get_position() - difference);5200}52015202void VisualShaderEditor::_param_filter_changed(const String &p_text) {5203param_filter_name = p_text;52045205if (!_update_preview_parameter_tree()) {5206_clear_preview_param();5207}5208}52095210void VisualShaderEditor::_param_property_changed(const String &p_property, const Variant &p_value, const String &p_field, bool p_changing) {5211if (p_changing) {5212return;5213}5214String raw_prop_name = p_property.trim_prefix("shader_parameter/");52155216EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();52175218undo_redo->create_action(vformat(TTR("Edit Preview Parameter: %s"), p_property));5219undo_redo->add_do_method(visual_shader.ptr(), "_set_preview_shader_parameter", raw_prop_name, p_value);5220undo_redo->add_undo_method(visual_shader.ptr(), "_set_preview_shader_parameter", raw_prop_name, preview_material->get(p_property));5221undo_redo->add_do_method(this, "_update_current_param");5222undo_redo->add_undo_method(this, "_update_current_param");5223undo_redo->commit_action();5224}52255226void VisualShaderEditor::_update_current_param() {5227if (current_prop != nullptr) {5228String name = current_prop->get_meta("id");5229if (visual_shader->_has_preview_shader_parameter(name)) {5230preview_material->set("shader_parameter/" + name, visual_shader->_get_preview_shader_parameter(name));5231} else {5232preview_material->set("shader_parameter/" + name, Variant());5233}5234current_prop->update_property();5235current_prop->update_editor_property_status();5236current_prop->update_cache();5237}5238}52395240void VisualShaderEditor::_param_selected() {5241_clear_preview_param();52425243TreeItem *item = parameters->get_selected();5244selected_param_id = item->get_meta("id");52455246PropertyInfo pi = parameter_props.get(selected_param_id);5247EditorProperty *prop = EditorInspector::instantiate_property_editor(preview_material.ptr(), pi.type, pi.name, pi.hint, pi.hint_string, pi.usage);5248if (!prop) {5249return;5250}5251prop->connect("property_changed", callable_mp(this, &VisualShaderEditor::_param_property_changed));5252prop->set_h_size_flags(SIZE_EXPAND_FILL);5253prop->set_object_and_property(preview_material.ptr(), "shader_parameter/" + pi.name);52545255prop->set_label(TTR("Value:"));5256prop->update_property();5257prop->update_editor_property_status();5258prop->update_cache();52595260current_prop = prop;5261current_prop->set_meta("id", selected_param_id);52625263param_vbox2->add_child(prop);5264param_vbox->show();5265}52665267void VisualShaderEditor::_param_unselected() {5268parameters->deselect_all();52695270_clear_preview_param();5271}52725273void VisualShaderEditor::_help_open() {5274OS::get_singleton()->shell_open(vformat("%s/tutorials/shaders/visual_shaders.html", GODOT_VERSION_DOCS_URL));5275}52765277void VisualShaderEditor::_notification(int p_what) {5278switch (p_what) {5279case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {5280if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/panning")) {5281graph->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")));5282graph->set_warped_panning(EDITOR_GET("editors/panning/warped_mouse_panning"));5283}5284if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/visual_editors")) {5285graph->set_minimap_opacity(EDITOR_GET("editors/visual_editors/minimap_opacity"));5286graph->set_grid_pattern((GraphEdit::GridPattern) int(EDITOR_GET("editors/visual_editors/grid_pattern")));5287graph->set_connection_lines_curvature(EDITOR_GET("editors/visual_editors/lines_curvature"));52885289_update_graph();5290}5291} break;52925293case NOTIFICATION_ENTER_TREE: {5294// collapse tree by default52955296TreeItem *category = members->get_root()->get_first_child();5297while (category) {5298category->set_collapsed(true);5299TreeItem *sub_category = category->get_first_child();5300while (sub_category) {5301sub_category->set_collapsed(true);5302sub_category = sub_category->get_next();5303}5304category = category->get_next();5305}53065307graph->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")));5308graph->set_warped_panning(EDITOR_GET("editors/panning/warped_mouse_panning"));5309} break;53105311case NOTIFICATION_THEME_CHANGED: {5312site_search->set_button_icon(get_editor_theme_icon(SNAME("ExternalLink")));5313highend_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));53145315param_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search")));53165317code_preview_button->set_button_icon(Control::get_editor_theme_icon(SNAME("Shader")));5318shader_preview_button->set_button_icon(Control::get_editor_theme_icon(SNAME("SubViewport")));53195320{5321Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");5322Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");5323Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");5324Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");5325Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");5326Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");5327Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");5328Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");5329Color error_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));53305331varying_error_label->add_theme_color_override(SceneStringName(font_color), error_color);53325333for (const String &E : keyword_list) {5334if (ShaderLanguage::is_control_flow_keyword(E)) {5335syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);5336} else {5337syntax_highlighter->add_keyword_color(E, keyword_color);5338}5339}53405341preview_text->begin_bulk_theme_override();5342preview_text->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)));5343preview_text->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts)));5344preview_text->add_theme_color_override(SceneStringName(font_color), text_color);5345preview_text->end_bulk_theme_override();53465347syntax_highlighter->set_number_color(number_color);5348syntax_highlighter->set_symbol_color(symbol_color);5349syntax_highlighter->set_function_color(function_color);5350syntax_highlighter->set_member_variable_color(members_color);5351syntax_highlighter->clear_color_regions();5352syntax_highlighter->add_color_region("/*", "*/", comment_color, false);5353syntax_highlighter->add_color_region("//", "", comment_color, true);53545355preview_text->clear_comment_delimiters();5356preview_text->add_comment_delimiter("/*", "*/", false);5357preview_text->add_comment_delimiter("//", "", true);53585359error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Panel")));5360error_label->begin_bulk_theme_override();5361error_label->add_theme_font_override(SceneStringName(font), get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts)));5362error_label->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts)));5363error_label->add_theme_color_override(SceneStringName(font_color), error_color);5364error_label->end_bulk_theme_override();5365}53665367tools->set_button_icon(get_editor_theme_icon(SNAME("Tools")));5368preview_tools->set_button_icon(get_editor_theme_icon(SNAME("Tools")));53695370cached_theme_base_scale = get_theme_default_base_scale();53715372if (is_visible_in_tree()) {5373_update_graph();5374} else {5375theme_dirty = true;5376}5377update_toggle_files_button();5378_update_options_menu();5379} break;53805381case NOTIFICATION_VISIBILITY_CHANGED: {5382update_toggle_files_button();5383if (theme_dirty && is_visible_in_tree()) {5384theme_dirty = false;5385_update_graph();5386}5387} break;53885389case NOTIFICATION_DRAG_BEGIN: {5390Dictionary dd = get_viewport()->gui_get_drag_data();5391if (members->is_visible_in_tree() && dd.has("id")) {5392members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);5393}5394} break;53955396case NOTIFICATION_DRAG_END: {5397members->set_drop_mode_flags(0);5398} break;5399}5400}54015402void VisualShaderEditor::_scroll_offset_changed(const Vector2 &p_scroll) {5403if (!shader_fully_loaded) {5404return;5405}54065407panning_debounce_timer->start();5408}54095410void VisualShaderEditor::_node_changed(int p_id) {5411if (is_visible_in_tree()) {5412_update_graph();5413}5414}54155416void VisualShaderEditor::_nodes_linked_to_frame_request(const TypedArray<StringName> &p_nodes, const StringName &p_frame) {5417Vector<int> node_ids;5418for (int i = 0; i < p_nodes.size(); i++) {5419node_ids.push_back(p_nodes[i].operator String().to_int());5420}5421frame_node_id_to_link_to = p_frame.operator String().to_int();5422nodes_link_to_frame_buffer = node_ids;5423}54245425void VisualShaderEditor::_frame_rect_changed(const GraphFrame *p_frame, const Rect2 &p_new_rect) {5426if (p_frame == nullptr) {5427return;5428}54295430int node_id = String(p_frame->get_name()).to_int();5431Ref<VisualShaderNodeResizableBase> vsnode = visual_shader->get_node(get_current_shader_type(), node_id);5432if (vsnode.is_null()) {5433return;5434}5435vsnode->set_size(p_new_rect.size / graph->get_zoom());5436}54375438void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, List<VisualShader::Connection> &r_connections) {5439VisualShader::Type type = (VisualShader::Type)p_type;54405441selection_center.x = 0.0f;5442selection_center.y = 0.0f;54435444HashSet<int> nodes;54455446for (int i = 0; i < graph->get_child_count(); i++) {5447GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));5448if (graph_element) {5449int id = String(graph_element->get_name()).to_int();54505451Ref<VisualShaderNode> node = visual_shader->get_node(type, id);5452Ref<VisualShaderNodeOutput> output = node;5453if (output.is_valid()) { // can't duplicate output5454continue;5455}54565457if (node.is_valid() && graph_element->is_selected()) {5458Vector2 pos = visual_shader->get_node_position(type, id);5459selection_center += pos;54605461CopyItem item;5462item.id = id;5463item.node = visual_shader->get_node(type, id)->duplicate();5464item.position = visual_shader->get_node_position(type, id);54655466Ref<VisualShaderNodeResizableBase> resizable_base = node;5467if (resizable_base.is_valid()) {5468item.size = resizable_base->get_size();5469}54705471Ref<VisualShaderNodeGroupBase> group = node;5472if (group.is_valid()) {5473item.group_inputs = group->get_inputs();5474item.group_outputs = group->get_outputs();5475}54765477Ref<VisualShaderNodeExpression> expression = node;5478if (expression.is_valid()) {5479item.expression = expression->get_expression();5480}54815482r_items.push_back(item);54835484nodes.insert(id);5485}5486}5487}54885489List<VisualShader::Connection> node_connections;5490visual_shader->get_node_connections(type, &node_connections);54915492for (const VisualShader::Connection &E : node_connections) {5493if (nodes.has(E.from_node) && nodes.has(E.to_node)) {5494r_connections.push_back(E);5495}5496}54975498selection_center /= (float)r_items.size();5499}55005501void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate) {5502EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();5503if (p_duplicate) {5504undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));5505} else {5506bool copy_buffer_empty = true;5507for (const CopyItem &item : copy_items_buffer) {5508if (!item.disabled) {5509copy_buffer_empty = false;5510break;5511}5512}5513if (copy_buffer_empty) {5514return;5515}55165517undo_redo->create_action(TTR("Paste VisualShader Node(s)"));5518}55195520VisualShader::Type type = (VisualShader::Type)p_type;55215522int base_id = visual_shader->get_valid_node_id(type);5523int id_from = base_id;5524HashMap<int, int> connection_remap; // Used for connections and frame attachments.5525HashSet<int> unsupported_set;5526HashSet<int> added_set;55275528for (CopyItem &item : r_items) {5529if (item.disabled) {5530unsupported_set.insert(item.id);5531continue;5532}5533connection_remap[item.id] = id_from;5534Ref<VisualShaderNode> node = item.node->duplicate();5535node->set_frame(-1); // Do not reattach nodes to frame (for now).55365537Ref<VisualShaderNodeResizableBase> resizable_base = Object::cast_to<VisualShaderNodeResizableBase>(node.ptr());5538if (resizable_base.is_valid()) {5539undo_redo->add_do_method(node.ptr(), "set_size", item.size);5540}55415542Ref<VisualShaderNodeFrame> frame = Object::cast_to<VisualShaderNodeFrame>(node.ptr());5543if (frame.is_valid()) {5544// Do not reattach nodes to frame (for now).5545undo_redo->add_do_method(node.ptr(), "set_attached_nodes", PackedInt32Array());5546}55475548Ref<VisualShaderNodeGroupBase> group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());5549if (group.is_valid()) {5550undo_redo->add_do_method(node.ptr(), "set_inputs", item.group_inputs);5551undo_redo->add_do_method(node.ptr(), "set_outputs", item.group_outputs);5552}55535554Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(node.ptr());5555if (expression.is_valid()) {5556undo_redo->add_do_method(node.ptr(), "set_expression", item.expression);5557}55585559undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, node, item.position + p_offset, id_from);5560undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_from, false, false);55615562added_set.insert(id_from);5563id_from++;5564}55655566// Attach nodes to frame.5567for (const CopyItem &item : r_items) {5568Ref<VisualShaderNode> node = item.node;5569if (node->get_frame() == -1) {5570continue;5571}55725573int new_node_id = connection_remap[item.id];5574int new_frame_id = node->get_frame();55755576if (connection_remap.has(new_frame_id)) {5577new_frame_id = connection_remap[new_frame_id];5578}55795580undo_redo->add_do_method(visual_shader.ptr(), "attach_node_to_frame", type, new_node_id, new_frame_id);5581undo_redo->add_do_method(graph_plugin.ptr(), "attach_node_to_frame", type, new_node_id, new_frame_id);5582}55835584// Connect nodes.5585for (const VisualShader::Connection &E : p_connections) {5586if (unsupported_set.has(E.from_node) || unsupported_set.has(E.to_node)) {5587continue;5588}55895590undo_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);5591undo_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);5592undo_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);5593}55945595id_from = base_id;5596for (const CopyItem &item : r_items) {5597if (item.disabled) {5598continue;5599}5600undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from);5601undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_from, false);5602id_from++;5603}56045605undo_redo->commit_action();56065607// Reselect nodes by excluding the other ones.5608for (int i = 0; i < graph->get_child_count(); i++) {5609GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));5610if (graph_element) {5611int id = String(graph_element->get_name()).to_int();5612if (added_set.has(id)) {5613graph_element->set_selected(true);5614} else {5615graph_element->set_selected(false);5616}5617}5618}5619}56205621void VisualShaderEditor::_clear_copy_buffer() {5622copy_items_buffer.clear();5623copy_connections_buffer.clear();5624}56255626void VisualShaderEditor::_duplicate_nodes() {5627int type = get_current_shader_type();56285629List<CopyItem> items;5630List<VisualShader::Connection> node_connections;56315632_dup_copy_nodes(type, items, node_connections);56335634if (items.is_empty()) {5635return;5636}56375638_dup_paste_nodes(type, items, node_connections, Vector2(10, 10) * EDSCALE, true);5639}56405641void VisualShaderEditor::_copy_nodes(bool p_cut) {5642_clear_copy_buffer();56435644_dup_copy_nodes(get_current_shader_type(), copy_items_buffer, copy_connections_buffer);56455646if (p_cut) {5647EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();5648undo_redo->create_action(TTR("Cut VisualShader Node(s)"));56495650List<int> ids;5651for (const CopyItem &E : copy_items_buffer) {5652ids.push_back(E.id);5653}56545655_delete_nodes(get_current_shader_type(), ids);56565657undo_redo->commit_action();5658}5659}56605661void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2 &p_custom_position) {5662if (copy_items_buffer.is_empty()) {5663return;5664}56655666int type = get_current_shader_type();56675668float scale = graph->get_zoom();56695670Vector2 mpos;5671if (p_use_custom_position) {5672mpos = p_custom_position;5673} else {5674mpos = graph->get_local_mouse_position();5675}56765677_dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_offset() / scale + mpos / scale - selection_center, false);5678}56795680void VisualShaderEditor::_type_selected(int p_id) {5681int offset = VisualShader::TYPE_VERTEX;5682if (mode & MODE_FLAGS_PARTICLES) {5683offset = VisualShader::TYPE_START;5684if (p_id + offset > VisualShader::TYPE_PROCESS) {5685custom_mode_box->set_visible(false);5686custom_mode_enabled = false;5687} else {5688custom_mode_box->set_visible(true);5689if (custom_mode_box->is_pressed()) {5690custom_mode_enabled = true;5691offset += 3;5692}5693}5694} else if (mode & MODE_FLAGS_SKY) {5695offset = VisualShader::TYPE_SKY;5696} else if (mode & MODE_FLAGS_FOG) {5697offset = VisualShader::TYPE_FOG;5698} else if (mode & MODE_FLAGS_TEXTURE_BLIT) {5699offset = VisualShader::TYPE_TEXTURE_BLIT;5700}57015702set_current_shader_type(VisualShader::Type(p_id + offset));5703_update_nodes();5704_update_graph();57055706graph->grab_focus(true);5707}57085709void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) {5710if (!(mode & MODE_FLAGS_PARTICLES)) {5711return;5712}5713custom_mode_enabled = p_enabled;5714int id = edit_type->get_selected() + 3;5715if (p_enabled) {5716set_current_shader_type(VisualShader::Type(id + 3));5717} else {5718set_current_shader_type(VisualShader::Type(id));5719}5720_update_options_menu();5721_update_graph();5722}57235724void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, const String &p_name) {5725String prev_name = p_input->get_input_name();57265727if (p_name == prev_name) {5728return;5729}57305731VisualShaderNode::PortType next_input_type = p_input->get_input_type_by_name(p_name);5732VisualShaderNode::PortType prev_input_type = p_input->get_input_type_by_name(prev_name);57335734bool type_changed = next_input_type != prev_input_type;57355736EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();5737undo_redo_man->create_action(TTR("Visual Shader Input Type Changed"));57385739undo_redo_man->add_do_method(p_input.ptr(), "set_input_name", p_name);5740undo_redo_man->add_undo_method(p_input.ptr(), "set_input_name", prev_name);57415742if (type_changed) {5743for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {5744VisualShader::Type type = VisualShader::Type(type_id);57455746int id = visual_shader->find_node_id(type, p_input);5747if (id != VisualShader::NODE_ID_INVALID) {5748bool is_expanded = p_input->is_output_port_expandable(0) && p_input->_is_output_port_expanded(0);57495750int type_size = 0;5751if (is_expanded) {5752switch (next_input_type) {5753case VisualShaderNode::PORT_TYPE_VECTOR_2D: {5754type_size = 2;5755} break;5756case VisualShaderNode::PORT_TYPE_VECTOR_3D: {5757type_size = 3;5758} break;5759case VisualShaderNode::PORT_TYPE_VECTOR_4D: {5760type_size = 4;5761} break;5762default:5763break;5764}5765}57665767List<VisualShader::Connection> conns;5768visual_shader->get_node_connections(type, &conns);5769for (const VisualShader::Connection &E : conns) {5770int cn_from_node = E.from_node;5771int cn_from_port = E.from_port;5772int cn_to_node = E.to_node;5773int cn_to_port = E.to_port;57745775if (cn_from_node == id) {5776bool 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));57775778if (is_incompatible_types || cn_from_port > type_size) {5779undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5780undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5781undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5782undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);5783}5784}5785}57865787undo_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);5789}5790}5791}57925793undo_redo_man->commit_action();5794}57955796void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, const String &p_name) {5797String prev_name = p_parameter_ref->get_parameter_name();57985799if (p_name == prev_name) {5800return;5801}58025803bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name);58045805EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();5806undo_redo_man->create_action(TTR("ParameterRef Name Changed"));58075808undo_redo_man->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);5809undo_redo_man->add_undo_method(p_parameter_ref.ptr(), "set_parameter_name", prev_name);58105811// update output port5812for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {5813VisualShader::Type type = VisualShader::Type(type_id);5814int id = visual_shader->find_node_id(type, p_parameter_ref);5815if (id != VisualShader::NODE_ID_INVALID) {5816if (type_changed) {5817List<VisualShader::Connection> conns;5818visual_shader->get_node_connections(type, &conns);5819for (const VisualShader::Connection &E : conns) {5820if (E.from_node == id) {5821if (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))) {5822continue;5823}5824undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5825undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5826undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5827undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5828}5829}5830}5831undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);5832undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);5833break;5834}5835}58365837undo_redo_man->commit_action();5838}58395840void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_varying, const String &p_name) {5841String prev_name = p_varying->get_varying_name();58425843if (p_name == prev_name) {5844return;5845}58465847bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();58485849EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();5850undo_redo_man->create_action(TTR("Varying Name Changed"));58515852undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_name", p_name);5853undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_name", prev_name);58545855VisualShader::VaryingType vtype = p_varying->get_varying_type_by_name(p_name);5856VisualShader::VaryingType prev_vtype = p_varying->get_varying_type_by_name(prev_name);58575858bool type_changed = vtype != prev_vtype;58595860if (type_changed) {5861undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_type", vtype);5862undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_type", prev_vtype);5863}58645865// update ports5866for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {5867VisualShader::Type type = VisualShader::Type(type_id);5868int id = visual_shader->find_node_id(type, p_varying);58695870if (id != VisualShader::NODE_ID_INVALID) {5871if (type_changed) {5872List<VisualShader::Connection> conns;5873visual_shader->get_node_connections(type, &conns);58745875for (const VisualShader::Connection &E : conns) {5876if (is_getter) {5877if (E.from_node == id) {5878if (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))) {5879continue;5880}5881undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5882undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5883undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5884undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5885}5886} else {5887if (E.to_node == id) {5888if (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))) {5889continue;5890}5891undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5892undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5893undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5894undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);5895}5896}5897}5898}58995900undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);5901undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);5902break;5903}5904}59055906undo_redo_man->commit_action();5907}59085909void VisualShaderEditor::_float_constant_selected(int p_which) {5910ERR_FAIL_INDEX(p_which, MAX_FLOAT_CONST_DEFS);59115912VisualShader::Type type = get_current_shader_type();5913Ref<VisualShaderNodeFloatConstant> node = visual_shader->get_node(type, selected_float_constant);5914ERR_FAIL_COND(node.is_null());59155916if (Math::is_equal_approx(node->get_constant(), float_constant_defs[p_which].value)) {5917return; // same5918}59195920EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();5921undo_redo->create_action(vformat(TTR("Set Constant: %s"), float_constant_defs[p_which].name));5922undo_redo->add_do_method(node.ptr(), "set_constant", float_constant_defs[p_which].value);5923undo_redo->add_undo_method(node.ptr(), "set_constant", node->get_constant());5924undo_redo->commit_action();5925}59265927void VisualShaderEditor::_member_filter_changed(const String &p_text) {5928_update_options_menu();5929}59305931void VisualShaderEditor::_member_selected() {5932TreeItem *item = members->get_selected();59335934if (item != nullptr && item->has_meta("id")) {5935members_dialog->get_ok_button()->set_disabled(false);5936highend_label->set_visible(add_options[item->get_meta("id")].highend);5937node_desc->set_text(_get_description(item->get_meta("id")));5938} else {5939highend_label->set_visible(false);5940members_dialog->get_ok_button()->set_disabled(true);5941node_desc->set_text("");5942}5943}59445945void VisualShaderEditor::_member_create() {5946TreeItem *item = members->get_selected();5947if (item != nullptr && item->has_meta("id")) {5948int idx = members->get_selected()->get_meta("id");5949if (connection_node_insert_requested) {5950from_node = String(clicked_connection->from_node).to_int();5951from_slot = clicked_connection->from_port;5952to_node = String(clicked_connection->to_node).to_int();5953to_slot = clicked_connection->to_port;59545955connection_node_insert_requested = false;59565957saved_node_pos_dirty = true;59585959// Find both graph nodes and get their positions.5960GraphNode *from_graph_element = Object::cast_to<GraphNode>(graph->get_node(itos(from_node)));5961GraphNode *to_graph_element = Object::cast_to<GraphNode>(graph->get_node(itos(to_node)));59625963ERR_FAIL_NULL(from_graph_element);5964ERR_FAIL_NULL(to_graph_element);59655966// Since the size of the node to add is not known yet, it's not possible to center it exactly.5967float zoom = graph->get_zoom();5968saved_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));5969}5970_add_node(idx, add_options[idx].ops);5971members_dialog->hide();5972}5973}59745975void VisualShaderEditor::_member_cancel() {5976to_node = -1;5977to_slot = -1;5978from_node = -1;5979from_slot = -1;5980connection_node_insert_requested = false;5981}59825983void VisualShaderEditor::_update_varying_tree() {5984varyings->clear();5985TreeItem *root = varyings->create_item();59865987int count = visual_shader->get_varyings_count();59885989for (int i = 0; i < count; i++) {5990const VisualShader::Varying *varying = visual_shader->get_varying_by_index(i);59915992if (varying) {5993TreeItem *item = varyings->create_item(root);5994item->set_text(0, varying->name);59955996if (i == 0) {5997item->select(0);5998}59996000switch (varying->type) {6001case VisualShader::VARYING_TYPE_FLOAT:6002item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)));6003break;6004case VisualShader::VARYING_TYPE_INT:6005item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)));6006break;6007case VisualShader::VARYING_TYPE_UINT:6008item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)));6009break;6010case VisualShader::VARYING_TYPE_VECTOR_2D:6011item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)));6012break;6013case VisualShader::VARYING_TYPE_VECTOR_3D:6014item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)));6015break;6016case VisualShader::VARYING_TYPE_VECTOR_4D:6017item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)));6018break;6019case VisualShader::VARYING_TYPE_BOOLEAN:6020item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)));6021break;6022case VisualShader::VARYING_TYPE_TRANSFORM:6023item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)));6024break;6025default:6026break;6027}6028}6029}60306031varying_button->get_popup()->set_item_disabled(int(VaryingMenuOptions::REMOVE), count == 0);6032}60336034void VisualShaderEditor::_varying_create() {6035_add_varying(varying_name->get_text(), (VisualShader::VaryingMode)varying_mode->get_selected(), (VisualShader::VaryingType)varying_type->get_selected());6036add_varying_dialog->hide();6037}60386039void VisualShaderEditor::_varying_validate() {6040bool has_error = false;6041String error;6042String varname = varying_name->get_text();60436044if (!varname.is_valid_ascii_identifier()) {6045error += TTR("Invalid name for varying.");6046has_error = true;6047} else if (visual_shader->has_varying(varname)) {6048error += TTR("Varying with that name already exists.");6049has_error = true;6050}60516052if (varying_type->get_selected() == 6 && varying_mode->get_selected() == VisualShader::VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {6053if (has_error) {6054error += "\n";6055}6056error += vformat(TTR("Boolean type cannot be used with `%s` varying mode."), U"Vertex → [Fragment, Light]");6057has_error = true;6058}60596060if (has_error) {6061varying_error_label->show();6062varying_error_label->set_text(error);6063add_varying_dialog->get_ok_button()->set_disabled(true);6064} else {6065varying_error_label->hide();6066varying_error_label->set_text("");6067add_varying_dialog->get_ok_button()->set_disabled(false);6068}6069add_varying_dialog->reset_size();6070}60716072void VisualShaderEditor::_varying_type_changed(int p_index) {6073_varying_validate();6074}60756076void VisualShaderEditor::_varying_mode_changed(int p_index) {6077_varying_validate();6078}60796080void VisualShaderEditor::_varying_name_changed(const String &p_name) {6081_varying_validate();6082}60836084void VisualShaderEditor::_varying_deleted() {6085TreeItem *item = varyings->get_selected();60866087if (item != nullptr) {6088_remove_varying(item->get_text(0));6089remove_varying_dialog->hide();6090}6091}60926093void VisualShaderEditor::_varying_selected() {6094add_varying_dialog->get_ok_button()->set_disabled(false);6095}60966097void VisualShaderEditor::_varying_unselected() {6098add_varying_dialog->get_ok_button()->set_disabled(true);6099}61006101void VisualShaderEditor::_tools_menu_option(int p_idx) {6102TreeItem *category = members->get_root()->get_first_child();61036104switch (p_idx) {6105case EXPAND_ALL:61066107while (category) {6108category->set_collapsed(false);6109TreeItem *sub_category = category->get_first_child();6110while (sub_category) {6111sub_category->set_collapsed(false);6112sub_category = sub_category->get_next();6113}6114category = category->get_next();6115}61166117break;61186119case COLLAPSE_ALL:61206121while (category) {6122category->set_collapsed(true);6123TreeItem *sub_category = category->get_first_child();6124while (sub_category) {6125sub_category->set_collapsed(true);6126sub_category = sub_category->get_next();6127}6128category = category->get_next();6129}61306131break;6132default:6133break;6134}6135}61366137void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {6138switch (p_idx) {6139case NodeMenuOptions::ADD:6140_show_members_dialog(true);6141break;6142case NodeMenuOptions::CUT:6143_copy_nodes(true);6144break;6145case NodeMenuOptions::COPY:6146_copy_nodes(false);6147break;6148case NodeMenuOptions::PASTE:6149_paste_nodes(true, menu_point);6150break;6151case NodeMenuOptions::DELETE_:6152_delete_nodes_request(TypedArray<StringName>());6153break;6154case NodeMenuOptions::DUPLICATE:6155_duplicate_nodes();6156break;6157case NodeMenuOptions::CLEAR_COPY_BUFFER:6158_clear_copy_buffer();6159break;6160case NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS:6161_convert_constants_to_parameters(false);6162break;6163case NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS:6164_convert_constants_to_parameters(true);6165break;6166case NodeMenuOptions::UNLINK_FROM_PARENT_FRAME:6167_detach_nodes_from_frame_request();6168break;6169case NodeMenuOptions::SET_FRAME_TITLE:6170_frame_title_popup_show(get_screen_position() + get_local_mouse_position(), selected_frame);6171break;6172case NodeMenuOptions::ENABLE_FRAME_COLOR:6173_frame_color_enabled_changed(selected_frame);6174break;6175case NodeMenuOptions::SET_FRAME_COLOR:6176_frame_color_popup_show(get_screen_position() + get_local_mouse_position(), selected_frame);6177break;6178case NodeMenuOptions::ENABLE_FRAME_AUTOSHRINK:6179_frame_autoshrink_enabled_changed(selected_frame);6180break;6181default:6182break;6183}6184}61856186void VisualShaderEditor::_connection_menu_id_pressed(int p_idx) {6187switch (p_idx) {6188case ConnectionMenuOptions::DISCONNECT: {6189EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();6190undo_redo->create_action(TTR("Disconnect"));6191undo_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);6192undo_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);6193undo_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);6194undo_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);6195undo_redo->commit_action();6196} break;6197case ConnectionMenuOptions::INSERT_NEW_NODE: {6198VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;6199VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;6200Ref<VisualShaderNode> node1 = visual_shader->get_node(get_current_shader_type(), String(clicked_connection->from_node).to_int());6201if (node1.is_valid()) {6202output_port_type = node1->get_output_port_type(from_slot);6203}6204Ref<VisualShaderNode> node2 = visual_shader->get_node(get_current_shader_type(), String(clicked_connection->to_node).to_int());6205if (node2.is_valid()) {6206input_port_type = node2->get_input_port_type(to_slot);6207}62086209connection_node_insert_requested = true;6210_show_members_dialog(true, input_port_type, output_port_type);6211} break;6212case ConnectionMenuOptions::INSERT_NEW_REROUTE: {6213from_node = String(clicked_connection->from_node).to_int();6214from_slot = clicked_connection->from_port;6215to_node = String(clicked_connection->to_node).to_int();6216to_slot = clicked_connection->to_port;62176218// Manual offset to place the port exactly at the mouse position.6219saved_node_pos -= Vector2(11 * EDSCALE * graph->get_zoom(), 50 * EDSCALE * graph->get_zoom());62206221// Find reroute addoptions.6222int idx = -1;6223for (int i = 0; i < add_options.size(); i++) {6224if (add_options[i].name == "Reroute") {6225idx = i;6226break;6227}6228}6229_add_node(idx, add_options[idx].ops);6230} break;6231default:6232break;6233}6234}62356236Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {6237if (p_point == Vector2(Math::INF, Math::INF)) {6238return Variant();6239}62406241if (p_from == members) {6242TreeItem *it = members->get_item_at_position(p_point);6243if (!it) {6244return Variant();6245}6246if (!it->has_meta("id")) {6247return Variant();6248}62496250int id = it->get_meta("id");6251AddOption op = add_options[id];62526253Dictionary d;6254d["id"] = id;62556256Label *label = memnew(Label);6257label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6258label->set_text(it->get_text(0));6259label->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);6260set_drag_preview(label);6261return d;6262}6263return Variant();6264}62656266bool VisualShaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {6267if (p_point == Vector2(Math::INF, Math::INF)) {6268return false;6269}62706271if (p_from == graph) {6272Dictionary d = p_data;62736274if (d.has("id")) {6275return true;6276}6277if (d.has("files")) {6278return true;6279}6280}62816282return false;6283}62846285void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {6286if (p_point == Vector2(Math::INF, Math::INF)) {6287return;6288}62896290if (p_from == graph) {6291Dictionary d = p_data;62926293if (d.has("id")) {6294int idx = d["id"];6295saved_node_pos = p_point;6296saved_node_pos_dirty = true;6297_add_node(idx, add_options[idx].ops);6298} else if (d.has("files")) {6299EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();6300undo_redo->create_action(TTR("Add Node(s) to Visual Shader"));63016302if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) {6303PackedStringArray arr = d["files"];6304for (int i = 0; i < arr.size(); i++) {6305String type = ResourceLoader::get_resource_type(arr[i]);6306if (type == "GDScript") {6307Ref<Script> scr = ResourceLoader::load(arr[i]);6308if (scr->get_instance_base_type() == "VisualShaderNodeCustom") {6309saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6310saved_node_pos_dirty = true;63116312int idx = -1;63136314for (int j = custom_node_option_idx; j < add_options.size(); j++) {6315if (add_options[j].script.is_valid()) {6316if (add_options[j].script->get_path() == arr[i]) {6317idx = j;6318break;6319}6320}6321}6322if (idx != -1) {6323_add_node(idx, {}, arr[i], i);6324}6325}6326} else if (type == "CurveTexture") {6327saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6328saved_node_pos_dirty = true;6329_add_node(curve_node_option_idx, {}, arr[i], i);6330} else if (type == "CurveXYZTexture") {6331saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6332saved_node_pos_dirty = true;6333_add_node(curve_xyz_node_option_idx, {}, arr[i], i);6334} else if (ClassDB::get_parent_class(type) == "Texture2D") {6335saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6336saved_node_pos_dirty = true;6337_add_node(texture2d_node_option_idx, {}, arr[i], i);6338} else if (type == "Texture2DArray") {6339saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6340saved_node_pos_dirty = true;6341_add_node(texture2d_array_node_option_idx, {}, arr[i], i);6342} else if (ClassDB::get_parent_class(type) == "Texture3D") {6343saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6344saved_node_pos_dirty = true;6345_add_node(texture3d_node_option_idx, {}, arr[i], i);6346} else if (type == "Cubemap") {6347saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6348saved_node_pos_dirty = true;6349_add_node(cubemap_node_option_idx, {}, arr[i], i);6350} else if (type == "Mesh" && visual_shader->get_mode() == Shader::MODE_PARTICLES &&6351(get_current_shader_type() == VisualShader::TYPE_START || get_current_shader_type() == VisualShader::TYPE_START_CUSTOM)) {6352saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);6353saved_node_pos_dirty = true;6354_add_node(mesh_emitter_option_idx, {}, arr[i], i);6355}6356}6357}6358undo_redo->commit_action();6359}6360}6361}63626363void VisualShaderEditor::_show_preview_text() {6364code_preview_showed = !code_preview_showed;6365if (code_preview_showed) {6366if (code_preview_first) {6367code_preview_window->set_size(Size2(400 * EDSCALE, 600 * EDSCALE));6368code_preview_window->popup_centered();6369code_preview_first = false;6370} else {6371code_preview_window->popup();6372}63736374if (pending_update_preview) {6375_update_preview();6376pending_update_preview = false;6377}6378} else {6379code_preview_window->hide();6380}6381}63826383void VisualShaderEditor::_preview_close_requested() {6384code_preview_showed = false;6385code_preview_button->set_pressed(false);6386}63876388static ShaderLanguage::DataType _visual_shader_editor_get_global_shader_uniform_type(const StringName &p_variable) {6389RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_variable);6390return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);6391}63926393void VisualShaderEditor::_update_preview() {6394if (!code_preview_showed) {6395pending_update_preview = true;6396return;6397}63986399String code = visual_shader->get_code();64006401preview_text->set_text(code);64026403ShaderLanguage::ShaderCompileInfo info;6404info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode()));6405info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));6406info.stencil_modes = ShaderTypes::get_singleton()->get_stencil_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));6407info.shader_types = ShaderTypes::get_singleton()->get_types();6408info.global_shader_uniform_type_func = _visual_shader_editor_get_global_shader_uniform_type;64096410for (int i = 0; i < preview_text->get_line_count(); i++) {6411preview_text->set_line_background_color(i, Color(0, 0, 0, 0));6412}64136414String preprocessed_code;6415{6416String path = visual_shader->get_path();6417String error_pp;6418List<ShaderPreprocessor::FilePosition> err_positions;6419ShaderPreprocessor preprocessor;6420Error err = preprocessor.preprocess(code, path, preprocessed_code, &error_pp, &err_positions);6421if (err != OK) {6422ERR_FAIL_COND(err_positions.is_empty());64236424String file = err_positions.front()->get().file;6425int err_line = err_positions.front()->get().line;6426Color error_line_color = EDITOR_GET("text_editor/theme/highlighting/mark_color");6427preview_text->set_line_background_color(err_line - 1, error_line_color);6428error_panel->show();64296430error_label->set_text("error(" + file + ":" + itos(err_line) + "): " + error_pp);6431shader_error = true;6432return;6433}6434}64356436ShaderLanguage sl;6437Error err = sl.compile(preprocessed_code, info);6438if (err != OK) {6439int err_line;6440String err_text;6441Vector<ShaderLanguage::FilePosition> include_positions = sl.get_include_positions();6442if (include_positions.size() > 1) {6443// Error is in an include.6444err_line = include_positions[0].line;6445err_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();6446} else {6447err_line = sl.get_error_line();6448err_text = "error(" + itos(err_line) + "): " + sl.get_error_text();6449}64506451Color error_line_color = EDITOR_GET("text_editor/theme/highlighting/mark_color");6452preview_text->set_line_background_color(err_line - 1, error_line_color);6453error_panel->show();64546455error_label->set_text(err_text);6456shader_error = true;6457} else {6458error_panel->hide();6459shader_error = false;6460}6461}64626463void VisualShaderEditor::_update_next_previews(int p_node_id) {6464VisualShader::Type type = get_current_shader_type();64656466LocalVector<int> nodes;6467_get_next_nodes_recursively(type, p_node_id, nodes);64686469for (int node_id : nodes) {6470if (graph_plugin->is_preview_visible(node_id)) {6471graph_plugin->update_node_deferred(type, node_id);6472}6473}6474}64756476void VisualShaderEditor::_get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const {6477const LocalVector<int> &next_connections = visual_shader->get_next_connected_nodes(p_type, p_node_id);64786479for (int node_id : next_connections) {6480r_nodes.push_back(node_id);6481_get_next_nodes_recursively(p_type, node_id, r_nodes);6482}6483}64846485void VisualShaderEditor::_visibility_changed() {6486if (!is_visible()) {6487if (code_preview_window->is_visible()) {6488code_preview_button->set_pressed(false);6489code_preview_window->hide();6490code_preview_showed = false;6491}6492}6493}64946495void VisualShaderEditor::_show_shader_preview() {6496shader_preview_showed = !shader_preview_showed;6497if (shader_preview_showed) {6498shader_preview_vbox->show();6499} else {6500shader_preview_vbox->hide();65016502_param_unselected();6503}6504}65056506void VisualShaderEditor::set_toggle_list_control(Control *p_toggle_list_control) {6507toggle_files_list = p_toggle_list_control;6508}65096510void VisualShaderEditor::_toggle_files_pressed() {6511ERR_FAIL_NULL(toggle_files_list);6512toggle_files_list->set_visible(!toggle_files_list->is_visible());6513update_toggle_files_button();6514}65156516void VisualShaderEditor::_bind_methods() {6517ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes);6518ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);6519ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);6520ClassDB::bind_method("_parameter_ref_select_item", &VisualShaderEditor::_parameter_ref_select_item);6521ClassDB::bind_method("_varying_select_item", &VisualShaderEditor::_varying_select_item);6522ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);6523ClassDB::bind_method("_update_parameters", &VisualShaderEditor::_update_parameters);6524ClassDB::bind_method("_update_varyings", &VisualShaderEditor::_update_varyings);6525ClassDB::bind_method("_update_varying_tree", &VisualShaderEditor::_update_varying_tree);6526ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);6527ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);6528ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter);6529ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews);6530ClassDB::bind_method("_update_current_param", &VisualShaderEditor::_update_current_param);6531}65326533VisualShaderEditor::VisualShaderEditor() {6534vs_editor_cache.instantiate();6535vs_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));65366537ShaderLanguage::get_keyword_list(&keyword_list);6538EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::_resource_saved));6539FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created));6540FileSystemDock::get_singleton()->connect("resource_removed", callable_mp(this, &VisualShaderEditor::_resource_removed));65416542HSplitContainer *main_box = memnew(HSplitContainer);6543main_box->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);6544add_child(main_box);65456546graph = memnew(GraphEdit);6547graph->set_v_size_flags(SIZE_EXPAND_FILL);6548graph->set_h_size_flags(SIZE_EXPAND_FILL);6549graph->set_custom_minimum_size(Size2(200 * EDSCALE, 0));6550graph->set_grid_pattern(GraphEdit::GridPattern::GRID_PATTERN_DOTS);6551int grid_pattern = EDITOR_GET("editors/visual_editors/grid_pattern");6552graph->set_grid_pattern((GraphEdit::GridPattern)grid_pattern);6553graph->set_show_zoom_label(true);6554main_box->add_child(graph);6555SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor);6556float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");6557graph->set_minimap_opacity(graph_minimap_opacity);6558float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");6559graph->set_connection_lines_curvature(graph_lines_curvature);6560graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);6561graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT);6562graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT);6563graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);6564graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_2D);6565graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_3D);6566graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_4D);6567graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_TRANSFORM);6568graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SAMPLER);6569//graph->add_valid_left_disconnect_type(0);6570graph->set_v_size_flags(SIZE_EXPAND_FILL);6571graph->connect("connection_request", callable_mp(this, &VisualShaderEditor::_connection_request), CONNECT_DEFERRED);6572graph->connect("disconnection_request", callable_mp(this, &VisualShaderEditor::_disconnection_request), CONNECT_DEFERRED);6573graph->connect("node_selected", callable_mp(this, &VisualShaderEditor::_node_selected));6574graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_offset_changed));6575graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes));6576graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(false));6577graph->connect("cut_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(true));6578graph->connect("paste_nodes_request", callable_mp(this, &VisualShaderEditor::_paste_nodes).bind(false, Point2()));6579graph->connect("delete_nodes_request", callable_mp(this, &VisualShaderEditor::_delete_nodes_request));6580graph->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_graph_gui_input));6581graph->connect("connection_to_empty", callable_mp(this, &VisualShaderEditor::_connection_to_empty));6582graph->connect("connection_from_empty", callable_mp(this, &VisualShaderEditor::_connection_from_empty));6583graph->connect("connection_drag_ended", callable_mp(this, &VisualShaderEditor::_connection_drag_ended));6584graph->connect(SceneStringName(visibility_changed), callable_mp(this, &VisualShaderEditor::_visibility_changed));6585graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);6586graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT);6587graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6588graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_2D);6589graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_3D);6590graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_4D);6591graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN);65926593graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR);6594graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT);6595graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6596graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_2D);6597graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_3D);6598graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_4D);6599graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_BOOLEAN);66006601graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR);6602graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR_INT);6603graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6604graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_2D);6605graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_3D);6606graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_4D);6607graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_BOOLEAN);66086609graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR);6610graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR_INT);6611graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6612graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_2D);6613graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_3D);6614graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_4D);6615graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_BOOLEAN);66166617graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR);6618graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR_INT);6619graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6620graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_2D);6621graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_3D);6622graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_4D);6623graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_BOOLEAN);66246625graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR);6626graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR_INT);6627graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6628graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_2D);6629graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_3D);6630graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_4D);6631graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_BOOLEAN);66326633graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR);6634graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_INT);6635graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_UINT);6636graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_2D);6637graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_3D);6638graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_4D);6639graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN);66406641graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);6642graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER);66436644info_label = memnew(Label);6645info_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6646info_label->set_text(vformat(TTR("Hold %s Key To Swap Connections"), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL)));6647info_label->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_WIDE, PRESET_MODE_MINSIZE, 20);6648info_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);6649info_label->hide();6650graph->get_top_layer()->add_child(info_label);66516652PanelContainer *toolbar_panel = static_cast<PanelContainer *>(graph->get_menu_hbox()->get_parent());6653toolbar_panel->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE, PRESET_MODE_MINSIZE, 10);6654toolbar_panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);66556656toolbar_hflow = memnew(HFlowContainer);6657{6658LocalVector<Node *> nodes;6659for (int i = 0; i < graph->get_menu_hbox()->get_child_count(); i++) {6660Node *child = graph->get_menu_hbox()->get_child(i);6661nodes.push_back(child);6662}66636664for (Node *node : nodes) {6665graph->get_menu_hbox()->remove_child(node);6666toolbar_hflow->add_child(node);6667}66686669graph->get_menu_hbox()->hide();6670toolbar_panel->add_child(toolbar_hflow);6671}66726673VSeparator *vs = memnew(VSeparator);6674toolbar_hflow->add_child(vs);6675toolbar_hflow->move_child(vs, 0);66766677custom_mode_box = memnew(CheckBox);6678custom_mode_box->set_text(TTR("Custom"));6679custom_mode_box->set_pressed(false);6680custom_mode_box->set_visible(false);6681custom_mode_box->connect(SceneStringName(toggled), callable_mp(this, &VisualShaderEditor::_custom_mode_toggled));66826683edit_type_standard = memnew(OptionButton);6684edit_type_standard->add_item(TTR("Vertex"));6685edit_type_standard->add_item(TTR("Fragment"));6686edit_type_standard->add_item(TTR("Light"));6687edit_type_standard->select(1);6688edit_type_standard->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));66896690edit_type_particles = memnew(OptionButton);6691edit_type_particles->add_item(TTR("Start"));6692edit_type_particles->add_item(TTR("Process"));6693edit_type_particles->add_item(TTR("Collide"));6694edit_type_particles->select(0);6695edit_type_particles->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));66966697edit_type_sky = memnew(OptionButton);6698edit_type_sky->add_item(TTR("Sky"));6699edit_type_sky->select(0);6700edit_type_sky->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));67016702edit_type_fog = memnew(OptionButton);6703edit_type_fog->add_item(TTR("Fog"));6704edit_type_fog->select(0);6705edit_type_fog->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));67066707edit_type_texture_blit = memnew(OptionButton);6708edit_type_texture_blit->add_item(TTR("Blit"));6709edit_type_texture_blit->select(0);6710edit_type_texture_blit->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));67116712edit_type = edit_type_standard;67136714toolbar_hflow->add_child(custom_mode_box);6715toolbar_hflow->move_child(custom_mode_box, 0);6716toolbar_hflow->add_child(edit_type_standard);6717toolbar_hflow->move_child(edit_type_standard, 0);6718toolbar_hflow->add_child(edit_type_particles);6719toolbar_hflow->move_child(edit_type_particles, 0);6720toolbar_hflow->add_child(edit_type_sky);6721toolbar_hflow->move_child(edit_type_sky, 0);6722toolbar_hflow->add_child(edit_type_fog);6723toolbar_hflow->move_child(edit_type_fog, 0);6724toolbar_hflow->add_child(edit_type_texture_blit);6725toolbar_hflow->move_child(edit_type_texture_blit, 0);67266727add_node = memnew(Button);6728add_node->set_theme_type_variation(SceneStringName(FlatButton));6729add_node->set_text(TTR("Add Node..."));6730toolbar_hflow->add_child(add_node);6731toolbar_hflow->move_child(add_node, 0);6732add_node->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_members_dialog).bind(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX));67336734graph->connect("graph_elements_linked_to_frame_request", callable_mp(this, &VisualShaderEditor::_nodes_linked_to_frame_request));6735graph->connect("frame_rect_changed", callable_mp(this, &VisualShaderEditor::_frame_rect_changed));67366737varying_button = memnew(MenuButton);6738varying_button->set_flat(false);6739varying_button->set_theme_type_variation("FlatMenuButton");6740varying_button->set_text(TTR("Manage Varyings"));6741varying_button->set_switch_on_hover(true);6742toolbar_hflow->add_child(varying_button);67436744PopupMenu *varying_menu = varying_button->get_popup();6745varying_menu->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD));6746varying_menu->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE));6747varying_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed));67486749code_preview_button = memnew(Button);6750code_preview_button->set_theme_type_variation(SceneStringName(FlatButton));6751code_preview_button->set_toggle_mode(true);6752code_preview_button->set_tooltip_text(TTR("Show generated shader code."));6753toolbar_hflow->add_child(code_preview_button);6754code_preview_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_preview_text));67556756shader_preview_button = memnew(Button);6757shader_preview_button->set_theme_type_variation(SceneStringName(FlatButton));6758shader_preview_button->set_toggle_mode(true);6759shader_preview_button->set_tooltip_text(TTR("Toggle shader preview."));6760shader_preview_button->set_pressed(true);6761toolbar_hflow->add_child(shader_preview_button);6762shader_preview_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_show_shader_preview));67636764Control *spacer = memnew(Control);6765spacer->set_h_size_flags(Control::SIZE_EXPAND);6766toolbar_hflow->add_child(spacer);67676768site_search = memnew(Button);6769site_search->set_theme_type_variation(SceneStringName(FlatButton));6770site_search->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_help_open));6771site_search->set_text(TTR("Online Docs"));6772site_search->set_tooltip_text(TTR("Open Godot online documentation."));6773toolbar_hflow->add_child(site_search);67746775VSeparator *separator = memnew(VSeparator);6776toolbar_hflow->add_child(separator);6777toolbar_hflow->move_child(separator, 0);67786779separator = memnew(VSeparator);6780toolbar_hflow->add_child(separator);6781toolbar_hflow->move_child(separator, 0);67826783toggle_files_button = memnew(Button);6784toggle_files_button->set_theme_type_variation(SceneStringName(FlatButton));6785toggle_files_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_toggle_files_pressed));6786toolbar_hflow->add_child(toggle_files_button);6787toolbar_hflow->move_child(toggle_files_button, 0);67886789///////////////////////////////////////6790// CODE PREVIEW6791///////////////////////////////////////67926793code_preview_window = memnew(AcceptDialog);6794code_preview_window->set_title(TTR("Generated Shader Code"));6795code_preview_window->set_visible(code_preview_showed);6796code_preview_window->set_ok_button_text(TTR("Close"));6797code_preview_window->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_preview_close_requested));6798code_preview_window->connect("canceled", callable_mp(this, &VisualShaderEditor::_preview_close_requested));6799add_child(code_preview_window);68006801code_preview_vbox = memnew(VBoxContainer);6802code_preview_window->add_child(code_preview_vbox);6803code_preview_vbox->add_theme_constant_override("separation", 0);68046805preview_text = memnew(CodeEdit);6806syntax_highlighter.instantiate();6807code_preview_vbox->add_child(preview_text);6808preview_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);6809preview_text->set_syntax_highlighter(syntax_highlighter);6810preview_text->set_draw_line_numbers(true);6811preview_text->set_editable(false);68126813error_panel = memnew(PanelContainer);6814code_preview_vbox->add_child(error_panel);6815error_panel->set_visible(false);68166817error_label = memnew(Label);6818error_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6819error_panel->add_child(error_label);6820error_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);68216822///////////////////////////////////////6823// POPUP MENU6824///////////////////////////////////////68256826popup_menu = memnew(PopupMenu);6827add_child(popup_menu);6828popup_menu->set_hide_on_checkable_item_selection(false);6829popup_menu->add_item(TTR("Add Node"), NodeMenuOptions::ADD);6830popup_menu->add_separator();6831popup_menu->add_item(TTR("Cut"), NodeMenuOptions::CUT);6832popup_menu->add_item(TTR("Copy"), NodeMenuOptions::COPY);6833popup_menu->add_item(TTR("Paste"), NodeMenuOptions::PASTE);6834popup_menu->add_item(TTR("Delete"), NodeMenuOptions::DELETE_);6835popup_menu->add_item(TTR("Duplicate"), NodeMenuOptions::DUPLICATE);6836popup_menu->add_item(TTR("Clear Copy Buffer"), NodeMenuOptions::CLEAR_COPY_BUFFER);6837popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed));68386839connection_popup_menu = memnew(PopupMenu);6840add_child(connection_popup_menu);6841connection_popup_menu->add_item(TTR("Disconnect"), ConnectionMenuOptions::DISCONNECT);6842connection_popup_menu->add_item(TTR("Insert New Node"), ConnectionMenuOptions::INSERT_NEW_NODE);6843connection_popup_menu->add_item(TTR("Insert New Reroute"), ConnectionMenuOptions::INSERT_NEW_REROUTE);6844connection_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_connection_menu_id_pressed));68456846///////////////////////////////////////6847// SHADER PREVIEW6848///////////////////////////////////////68496850shader_preview_vbox = memnew(VBoxContainer);6851shader_preview_vbox->set_custom_minimum_size(Size2(200 * EDSCALE, 0));6852main_box->add_child(shader_preview_vbox);68536854VSplitContainer *preview_split = memnew(VSplitContainer);6855preview_split->set_v_size_flags(SIZE_EXPAND_FILL);6856shader_preview_vbox->add_child(preview_split);68576858// Initialize material editor.6859{6860env.instantiate();6861Ref<Sky> sky = memnew(Sky());6862env->set_sky(sky);6863env->set_background(Environment::BG_COLOR);6864env->set_ambient_source(Environment::AMBIENT_SOURCE_SKY);6865env->set_reflection_source(Environment::REFLECTION_SOURCE_SKY);68666867preview_material.instantiate();6868preview_material->connect(CoreStringName(property_list_changed), callable_mp(this, &VisualShaderEditor::_update_preview_parameter_list));68696870material_editor = memnew(MaterialEditor);6871preview_split->add_child(material_editor);6872}68736874VBoxContainer *params_vbox = memnew(VBoxContainer);6875preview_split->add_child(params_vbox);68766877HBoxContainer *filter_hbox = memnew(HBoxContainer);6878params_vbox->add_child(filter_hbox);68796880param_filter = memnew(LineEdit);6881filter_hbox->add_child(param_filter);6882param_filter->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_param_filter_changed));6883param_filter->set_h_size_flags(SIZE_EXPAND_FILL);6884param_filter->set_placeholder(TTR("Filter Parameters"));68856886preview_tools = memnew(MenuButton);6887filter_hbox->add_child(preview_tools);6888preview_tools->set_tooltip_text(TTR("Options"));6889preview_tools->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_preview_tools_menu_option));6890preview_tools->get_popup()->add_item(TTR("Copy Parameters From Material"), COPY_PARAMS_FROM_MATERIAL);6891preview_tools->get_popup()->add_item(TTR("Paste Parameters To Material"), PASTE_PARAMS_TO_MATERIAL);68926893ScrollContainer *sc = memnew(ScrollContainer);6894sc->set_v_size_flags(SIZE_EXPAND_FILL);6895params_vbox->add_child(sc);68966897parameters = memnew(Tree);6898parameters->set_hide_root(true);6899parameters->set_allow_reselect(true);6900parameters->set_hide_folding(false);6901parameters->set_h_size_flags(SIZE_EXPAND_FILL);6902parameters->set_v_size_flags(SIZE_EXPAND_FILL);6903parameters->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);6904parameters->set_theme_type_variation("TreeSecondary");6905parameters->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_param_selected));6906parameters->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_param_unselected));6907sc->add_child(parameters);69086909param_vbox = memnew(VBoxContainer);6910param_vbox->set_v_size_flags(SIZE_EXPAND_FILL);6911param_vbox->hide();6912params_vbox->add_child(param_vbox);69136914ScrollContainer *sc2 = memnew(ScrollContainer);6915sc2->set_v_size_flags(SIZE_EXPAND_FILL);6916param_vbox->add_child(sc2);69176918param_vbox2 = memnew(VBoxContainer);6919param_vbox2->set_h_size_flags(SIZE_EXPAND_FILL);6920sc2->add_child(param_vbox2);69216922///////////////////////////////////////6923// SHADER NODES TREE6924///////////////////////////////////////69256926VBoxContainer *members_vb = memnew(VBoxContainer);6927members_vb->set_v_size_flags(SIZE_EXPAND_FILL);69286929HBoxContainer *filter_hb = memnew(HBoxContainer);6930members_vb->add_child(filter_hb);69316932node_filter = memnew(FilterLineEdit);6933filter_hb->add_child(node_filter);6934node_filter->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_member_filter_changed));6935node_filter->set_h_size_flags(SIZE_EXPAND_FILL);6936node_filter->set_placeholder(TTR("Search"));69376938tools = memnew(MenuButton);6939filter_hb->add_child(tools);6940tools->set_tooltip_text(TTR("Options"));6941tools->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_tools_menu_option));6942tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL);6943tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL);69446945members = memnew(Tree);6946node_filter->set_forward_control(members);6947members_vb->add_child(members);6948SET_DRAG_FORWARDING_GCD(members, VisualShaderEditor);6949members->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.6950members->set_h_size_flags(SIZE_EXPAND_FILL);6951members->set_v_size_flags(SIZE_EXPAND_FILL);6952members->set_hide_root(true);6953members->set_allow_reselect(true);6954members->set_hide_folding(false);6955members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));6956members->connect("item_activated", callable_mp(this, &VisualShaderEditor::_member_create));6957members->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_member_selected));69586959HBoxContainer *desc_hbox = memnew(HBoxContainer);6960members_vb->add_child(desc_hbox);69616962Label *desc_label = memnew(Label);6963desc_hbox->add_child(desc_label);6964desc_label->set_text(TTR("Description:"));69656966desc_hbox->add_spacer();69676968highend_label = memnew(Label);6969highend_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);6970desc_hbox->add_child(highend_label);6971highend_label->set_visible(false);6972highend_label->set_text(TTRC("Forward+/Mobile"));6973highend_label->set_mouse_filter(Control::MOUSE_FILTER_STOP);6974highend_label->set_tooltip_text(TTR("Only supported in the Forward+ and Mobile rendering methods, not Compatibility."));69756976node_desc = memnew(RichTextLabel);6977members_vb->add_child(node_desc);6978node_desc->set_h_size_flags(SIZE_EXPAND_FILL);6979node_desc->set_v_size_flags(SIZE_FILL);6980node_desc->set_custom_minimum_size(Size2(0, 70 * EDSCALE));69816982members_dialog = memnew(ConfirmationDialog);6983members_dialog->set_title(TTR("Create Shader Node"));6984members_dialog->add_child(members_vb);6985members_dialog->set_ok_button_text(TTR("Create"));6986members_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_member_create));6987members_dialog->get_ok_button()->set_disabled(true);6988members_dialog->connect("canceled", callable_mp(this, &VisualShaderEditor::_member_cancel));6989members_dialog->register_text_enter(node_filter);6990add_child(members_dialog);69916992// add varyings dialog6993{6994add_varying_dialog = memnew(ConfirmationDialog);6995add_varying_dialog->set_title(TTR("Create Shader Varying"));6996add_varying_dialog->set_ok_button_text(TTR("Create"));6997add_varying_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_varying_create));6998add_varying_dialog->get_ok_button()->set_disabled(true);6999add_child(add_varying_dialog);70007001VBoxContainer *vb = memnew(VBoxContainer);7002add_varying_dialog->add_child(vb);70037004HBoxContainer *hb = memnew(HBoxContainer);7005vb->add_child(hb);7006hb->set_h_size_flags(SIZE_EXPAND_FILL);70077008varying_type = memnew(OptionButton);7009hb->add_child(varying_type);7010varying_type->add_item("Float");7011varying_type->add_item("Int");7012varying_type->add_item("UInt");7013varying_type->add_item("Vector2");7014varying_type->add_item("Vector3");7015varying_type->add_item("Vector4");7016varying_type->add_item("Boolean");7017varying_type->add_item("Transform");7018varying_type->set_accessibility_name(TTRC("Varying Type"));7019varying_type->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_varying_type_changed));70207021varying_name = memnew(LineEdit);7022hb->add_child(varying_name);7023varying_name->set_custom_minimum_size(Size2(150 * EDSCALE, 0));7024varying_name->set_h_size_flags(SIZE_EXPAND_FILL);7025varying_name->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_varying_name_changed));7026add_varying_dialog->register_text_enter(varying_name);70277028varying_mode = memnew(OptionButton);7029hb->add_child(varying_mode);7030varying_mode->add_item(U"Vertex → [Fragment, Light]");7031varying_mode->add_item(U"Fragment → Light");7032varying_mode->set_accessibility_name(TTRC("Varying Mode"));7033varying_mode->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_varying_mode_changed));70347035varying_error_label = memnew(Label);7036varying_error_label->set_focus_mode(Control::FOCUS_ACCESSIBILITY);7037vb->add_child(varying_error_label);7038varying_error_label->set_h_size_flags(SIZE_EXPAND_FILL);70397040varying_error_label->hide();7041}70427043// remove varying dialog7044{7045remove_varying_dialog = memnew(ConfirmationDialog);7046remove_varying_dialog->set_title(TTR("Delete Shader Varying"));7047remove_varying_dialog->set_ok_button_text(TTR("Delete"));7048remove_varying_dialog->connect(SceneStringName(confirmed), callable_mp(this, &VisualShaderEditor::_varying_deleted));7049add_child(remove_varying_dialog);70507051VBoxContainer *vb = memnew(VBoxContainer);7052remove_varying_dialog->add_child(vb);70537054varyings = memnew(Tree);7055vb->add_child(varyings);7056varyings->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);7057varyings->set_h_size_flags(SIZE_EXPAND_FILL);7058varyings->set_v_size_flags(SIZE_EXPAND_FILL);7059varyings->set_hide_root(true);7060varyings->set_allow_reselect(true);7061varyings->set_hide_folding(false);7062varyings->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));7063varyings->connect("item_activated", callable_mp(this, &VisualShaderEditor::_varying_deleted));7064varyings->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_varying_selected));7065varyings->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_varying_unselected));7066}70677068alert = memnew(AcceptDialog);7069alert->get_label()->set_autowrap_mode(TextServer::AUTOWRAP_WORD);7070alert->get_label()->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);7071alert->get_label()->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);7072alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);7073add_child(alert);70747075frame_title_change_popup = memnew(PopupPanel);7076frame_title_change_edit = memnew(LineEdit);7077frame_title_change_edit->set_expand_to_text_length_enabled(true);7078frame_title_change_edit->set_select_all_on_focus(true);7079frame_title_change_edit->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_frame_title_text_changed));7080frame_title_change_edit->connect(SceneStringName(text_submitted), callable_mp(this, &VisualShaderEditor::_frame_title_text_submitted));7081frame_title_change_popup->add_child(frame_title_change_edit);7082frame_title_change_edit->reset_size();7083frame_title_change_popup->reset_size();7084frame_title_change_popup->connect(SceneStringName(focus_exited), callable_mp(this, &VisualShaderEditor::_frame_title_popup_focus_out));7085frame_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_frame_title_popup_hide));7086add_child(frame_title_change_popup);70877088frame_tint_color_pick_popup = memnew(PopupPanel);7089VBoxContainer *frame_popup_item_tint_color_editor = memnew(VBoxContainer);7090frame_tint_color_pick_popup->add_child(frame_popup_item_tint_color_editor);7091frame_tint_color_picker = memnew(ColorPicker);7092frame_popup_item_tint_color_editor->add_child(frame_tint_color_picker);7093frame_tint_color_picker->reset_size();7094frame_tint_color_picker->connect("color_changed", callable_mp(this, &VisualShaderEditor::_frame_color_changed));7095Button *frame_tint_color_confirm_button = memnew(Button);7096frame_tint_color_confirm_button->set_text(TTR("OK"));7097frame_popup_item_tint_color_editor->add_child(frame_tint_color_confirm_button);7098frame_tint_color_confirm_button->connect(SceneStringName(pressed), callable_mp(this, &VisualShaderEditor::_frame_color_confirm));70997100frame_tint_color_pick_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_frame_color_popup_hide));7101add_child(frame_tint_color_pick_popup);71027103///////////////////////////////////////7104// SHADER NODES TREE OPTIONS7105///////////////////////////////////////71067107// COLOR71087109add_options.push_back(AddOption("ColorFunc", "Color/Common", "VisualShaderNodeColorFunc", TTR("Color function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7110add_options.push_back(AddOption("ColorOp", "Color/Common", "VisualShaderNodeColorOp", TTR("Color operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));71117112add_options.push_back(AddOption("Grayscale", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7113add_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));7114add_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));7115add_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));7116add_options.push_back(AddOption("Sepia", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), { VisualShaderNodeColorFunc::FUNC_SEPIA }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7117add_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));71187119add_options.push_back(AddOption("Burn", "Color/Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), { VisualShaderNodeColorOp::OP_BURN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7120add_options.push_back(AddOption("Darken", "Color/Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), { VisualShaderNodeColorOp::OP_DARKEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7121add_options.push_back(AddOption("Difference", "Color/Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), { VisualShaderNodeColorOp::OP_DIFFERENCE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7122add_options.push_back(AddOption("Dodge", "Color/Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), { VisualShaderNodeColorOp::OP_DODGE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7123add_options.push_back(AddOption("HardLight", "Color/Operators", "VisualShaderNodeColorOp", TTR("HardLight operator."), { VisualShaderNodeColorOp::OP_HARD_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7124add_options.push_back(AddOption("Lighten", "Color/Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), { VisualShaderNodeColorOp::OP_LIGHTEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7125add_options.push_back(AddOption("Overlay", "Color/Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), { VisualShaderNodeColorOp::OP_OVERLAY }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7126add_options.push_back(AddOption("Screen", "Color/Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), { VisualShaderNodeColorOp::OP_SCREEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7127add_options.push_back(AddOption("SoftLight", "Color/Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), { VisualShaderNodeColorOp::OP_SOFT_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));71287129add_options.push_back(AddOption("ColorConstant", "Color/Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7130add_options.push_back(AddOption("ColorParameter", "Color/Variables", "VisualShaderNodeColorParameter", TTR("Color parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));71317132// COMMON71337134add_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));7135add_options.push_back(AddOption("DerivativeFunc", "Common", "VisualShaderNodeDerivativeFunc", TTR("Derivative function."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY, true));71367137// CONDITIONAL71387139const String &compare_func_desc = TTR("Returns the boolean result of the %s comparison between two parameters.");71407141add_options.push_back(AddOption("Equal (==)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Equal (==)")), { VisualShaderNodeCompare::FUNC_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));7142add_options.push_back(AddOption("GreaterThan (>)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than (>)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));7143add_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));7144add_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));7145add_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));7146add_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));7147add_options.push_back(AddOption("LessThan (<)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), { VisualShaderNodeCompare::FUNC_LESS_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));7148add_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));7149add_options.push_back(AddOption("NotEqual (!=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), { VisualShaderNodeCompare::FUNC_NOT_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));7150add_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));7151add_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));7152add_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));7153add_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));7154add_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));7155add_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));7156add_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));7157add_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));71587159add_options.push_back(AddOption("Compare (==)", "Conditional/Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));7160add_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));71617162add_options.push_back(AddOption("BooleanConstant", "Conditional/Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));7163add_options.push_back(AddOption("BooleanParameter", "Conditional/Variables", "VisualShaderNodeBooleanParameter", TTR("Boolean parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));71647165// INPUT71667167const String translation_gdsl = "\n\n" + TTR("Translated to '%s' in Godot Shading Language.");7168const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.") + translation_gdsl;71697170// NODE3D-FOR-ALL71717172add_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));7173add_options.push_back(AddOption("Exposure", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "exposure", "EXPOSURE"), { "exposure" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));7174add_options.push_back(AddOption("InShadowPass", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "in_shadow_pass", "IN_SHADOW_PASS"), { "in_shadow_pass" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_SPATIAL));7175add_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));7176add_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));7177add_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));7178add_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));7179add_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));7180add_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));7181add_options.push_back(AddOption("Time", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));7182add_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));7183add_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));7184add_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));7185add_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));71867187// CANVASITEM-FOR-ALL71887189add_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));7190add_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));7191add_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));7192add_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));71937194// PARTICLES-FOR-ALL71957196add_options.push_back(AddOption("Active", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active", "ACTIVE"), { "active" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));7197add_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));7198add_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));7199add_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));7200add_options.push_back(AddOption("Delta", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta", "DELTA"), { "delta" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));7201add_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));7202add_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));7203add_options.push_back(AddOption("LifeTime", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime", "LIFETIME"), { "lifetime" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));7204add_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));7205add_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));7206add_options.push_back(AddOption("Restart", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart", "RESTART"), { "restart" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));7207add_options.push_back(AddOption("Time", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));7208add_options.push_back(AddOption("Transform", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform", "TRANSFORM"), { "transform" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));7209add_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));72107211/////////////////72127213add_options.push_back(AddOption("Input", "Input/Common", "VisualShaderNodeInput", TTR("Input parameter.")));72147215const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;7216const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.") + translation_gdsl;7217const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.") + translation_gdsl;7218const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.") + translation_gdsl;7219const String input_param_for_fog_shader_mode = TTR("'%s' input parameter for fog shader mode.") + translation_gdsl;7220const String input_param_for_texture_blit_shader_mode = TTR("'%s' input parameter for blit shader mode.") + translation_gdsl;7221const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.") + translation_gdsl;7222const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.") + translation_gdsl;7223const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.") + translation_gdsl;7224const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode.") + translation_gdsl;7225const String input_param_for_collide_shader_mode = TTR("'%s' input parameter for collide shader mode." + translation_gdsl);7226const String input_param_for_start_and_process_shader_mode = TTR("'%s' input parameter for start and process shader modes.") + translation_gdsl;7227const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes.") + translation_gdsl;7228const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;72297230// NODE3D INPUTS72317232add_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));7233add_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));7234add_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));7235add_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));7236add_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));7237add_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));7238add_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));7239add_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));7240add_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));7241add_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));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_SPATIAL));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_SPATIAL));7244add_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));7245add_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));7246add_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));7247add_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));7248add_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));7249add_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));7250add_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));7251add_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));7252add_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));7253add_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));72547255add_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));7256add_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));7257add_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));7258add_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));7259add_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));7260add_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));7261add_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));7262add_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));7263add_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));7264add_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));7265add_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));7266add_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));7267add_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));7268add_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));7269add_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));7270add_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));7271add_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));7272add_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));72737274add_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));7275add_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));7276add_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));7277add_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));7278add_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));7279add_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));7280add_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));7281add_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));7282add_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));7283add_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));7284add_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));7285add_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));7286add_options.push_back(AddOption("SpecularAmount", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular_amount", "SPECULAR_AMOUNT"), { "specular_amount" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7287add_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));72887289// CANVASITEM INPUTS72907291add_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));7292add_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));7293add_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));7294add_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));7295add_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));7296add_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));7297add_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));7298add_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));7299add_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));7300add_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));7301add_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));73027303add_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));7304add_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));7305add_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));7306add_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));7307add_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));7308add_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));7309add_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));7310add_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));7311add_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));7312add_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));7313add_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));73147315add_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));7316add_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));7317add_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));7318add_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));7319add_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));7320add_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));7321add_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));7322add_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));7323add_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));7324add_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));7325add_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));7326add_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));7327add_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));7328add_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));73297330// SKY INPUTS73317332add_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));7333add_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));7334add_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));7335add_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));7336add_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));7337add_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));7338add_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));7339add_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));7340add_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));7341add_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));7342add_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));7343add_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));7344add_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));7345add_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));7346add_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));7347add_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));7348add_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));7349add_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));7350add_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));7351add_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));7352add_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));7353add_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));7354add_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));7355add_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));7356add_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));7357add_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));7358add_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));7359add_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));73607361// FOG INPUTS73627363add_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));7364add_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));7365add_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));7366add_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));7367add_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));7368add_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));73697370// TEXTURE BLIT INPUTS7371add_options.push_back(AddOption("UV", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "uv", "UV"), { "uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));7372add_options.push_back(AddOption("Modulate", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Modulate", "MODULATE"), { "Modulate" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));7373add_options.push_back(AddOption("Fragcoord", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Fragcoord", "FRAGCOORD"), { "Fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));7374add_options.push_back(AddOption("Source Texture", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture", "source_texture"), { "Source Texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));7375add_options.push_back(AddOption("Source Texture 2", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture 2", "source_texture2"), { "Source Texture 2" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));7376add_options.push_back(AddOption("Source Texture 3", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture 3", "source_texture3"), { "Source Texture 3" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));7377add_options.push_back(AddOption("Source Texture 4", "Input/Texture_blit", "VisualShaderNodeInput", vformat(input_param_for_texture_blit_shader_mode, "Source Texture 4", "source_texture4"), { "Source Texture 4" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_BLIT, Shader::MODE_TEXTURE_BLIT));73787379// PARTICLES INPUTS73807381add_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));7382add_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));73837384// PARTICLES73857386add_options.push_back(AddOption("EmitParticle", "Particles", "VisualShaderNodeParticleEmit", "", {}, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));7387add_options.push_back(AddOption("ParticleAccelerator", "Particles", "VisualShaderNodeParticleAccelerator", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));7388add_options.push_back(AddOption("ParticleRandomness", "Particles", "VisualShaderNodeParticleRandomness", "", {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));7389add_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));73907391add_options.push_back(AddOption("BoxEmitter", "Particles/Emitters", "VisualShaderNodeParticleBoxEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));73927393mesh_emitter_option_idx = add_options.size();7394add_options.push_back(AddOption("MeshEmitter", "Particles/Emitters", "VisualShaderNodeParticleMeshEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));73957396add_options.push_back(AddOption("RingEmitter", "Particles/Emitters", "VisualShaderNodeParticleRingEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));7397add_options.push_back(AddOption("SphereEmitter", "Particles/Emitters", "VisualShaderNodeParticleSphereEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));73987399add_options.push_back(AddOption("ConeVelocity", "Particles/Velocity", "VisualShaderNodeParticleConeVelocity", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));74007401// SCALAR74027403add_options.push_back(AddOption("FloatFunc", "Scalar/Common", "VisualShaderNodeFloatFunc", TTR("Float function."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7404add_options.push_back(AddOption("FloatOp", "Scalar/Common", "VisualShaderNodeFloatOp", TTR("Float operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7405add_options.push_back(AddOption("IntFunc", "Scalar/Common", "VisualShaderNodeIntFunc", TTR("Integer function."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7406add_options.push_back(AddOption("IntOp", "Scalar/Common", "VisualShaderNodeIntOp", TTR("Integer operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7407add_options.push_back(AddOption("UIntFunc", "Scalar/Common", "VisualShaderNodeUIntFunc", TTR("Unsigned integer function."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7408add_options.push_back(AddOption("UIntOp", "Scalar/Common", "VisualShaderNodeUIntOp", TTR("Unsigned integer operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));74097410// CONSTANTS74117412for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {7413add_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));7414}7415// FUNCTIONS74167417add_options.push_back(AddOption("Abs", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR));7418add_options.push_back(AddOption("Abs", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeIntFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7419add_options.push_back(AddOption("ACos", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOS }, VisualShaderNode::PORT_TYPE_SCALAR));7420add_options.push_back(AddOption("ACosH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOSH }, VisualShaderNode::PORT_TYPE_SCALAR));7421add_options.push_back(AddOption("ASin", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASIN }, VisualShaderNode::PORT_TYPE_SCALAR));7422add_options.push_back(AddOption("ASinH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASINH }, VisualShaderNode::PORT_TYPE_SCALAR));7423add_options.push_back(AddOption("ATan", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATAN }, VisualShaderNode::PORT_TYPE_SCALAR));7424add_options.push_back(AddOption("ATan2", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeFloatOp::OP_ATAN2 }, VisualShaderNode::PORT_TYPE_SCALAR));7425add_options.push_back(AddOption("ATanH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATANH }, VisualShaderNode::PORT_TYPE_SCALAR));7426add_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));7427add_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));7428add_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));7429add_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));7430add_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));7431add_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));7432add_options.push_back(AddOption("Cos", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COS }, VisualShaderNode::PORT_TYPE_SCALAR));7433add_options.push_back(AddOption("CosH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COSH }, VisualShaderNode::PORT_TYPE_SCALAR));7434add_options.push_back(AddOption("Degrees", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeFloatFunc::FUNC_DEGREES }, VisualShaderNode::PORT_TYPE_SCALAR));7435add_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));7436add_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));7437add_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));7438add_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));7439add_options.push_back(AddOption("Exp", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-e Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP }, VisualShaderNode::PORT_TYPE_SCALAR));7440add_options.push_back(AddOption("Exp2", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP2 }, VisualShaderNode::PORT_TYPE_SCALAR));7441add_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));7442add_options.push_back(AddOption("Fract", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeFloatFunc::FUNC_FRACT }, VisualShaderNode::PORT_TYPE_SCALAR));7443add_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));7444add_options.push_back(AddOption("Log", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Natural logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG }, VisualShaderNode::PORT_TYPE_SCALAR));7445add_options.push_back(AddOption("Log2", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG2 }, VisualShaderNode::PORT_TYPE_SCALAR));7446add_options.push_back(AddOption("Max", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), { VisualShaderNodeFloatOp::OP_MAX }, VisualShaderNode::PORT_TYPE_SCALAR));7447add_options.push_back(AddOption("Min", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), { VisualShaderNodeFloatOp::OP_MIN }, VisualShaderNode::PORT_TYPE_SCALAR));7448add_options.push_back(AddOption("Mix", "Scalar/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two scalars."), { VisualShaderNodeMix::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));7449add_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));7450add_options.push_back(AddOption("Negate (*-1)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR));7451add_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));7452add_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));7453add_options.push_back(AddOption("OneMinus (1-)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), { VisualShaderNodeFloatFunc::FUNC_ONEMINUS }, VisualShaderNode::PORT_TYPE_SCALAR));7454add_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));7455add_options.push_back(AddOption("Radians", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeFloatFunc::FUNC_RADIANS }, VisualShaderNode::PORT_TYPE_SCALAR));7456add_options.push_back(AddOption("Reciprocal", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), { VisualShaderNodeFloatFunc::FUNC_RECIPROCAL }, VisualShaderNode::PORT_TYPE_SCALAR));7457add_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));7458add_options.push_back(AddOption("Round", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUND }, VisualShaderNode::PORT_TYPE_SCALAR));7459add_options.push_back(AddOption("RoundEven", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUNDEVEN }, VisualShaderNode::PORT_TYPE_SCALAR));7460add_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));7461add_options.push_back(AddOption("Sign", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR));7462add_options.push_back(AddOption("Sign", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeIntFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7463add_options.push_back(AddOption("Sin", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIN }, VisualShaderNode::PORT_TYPE_SCALAR));7464add_options.push_back(AddOption("SinH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SINH }, VisualShaderNode::PORT_TYPE_SCALAR));7465add_options.push_back(AddOption("Sqrt", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SQRT }, VisualShaderNode::PORT_TYPE_SCALAR));7466add_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));7467add_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));7468add_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));7469add_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));7470add_options.push_back(AddOption("Tan", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TAN }, VisualShaderNode::PORT_TYPE_SCALAR));7471add_options.push_back(AddOption("TanH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TANH }, VisualShaderNode::PORT_TYPE_SCALAR));7472add_options.push_back(AddOption("Trunc", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TRUNC }, VisualShaderNode::PORT_TYPE_SCALAR));74737474add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), { VisualShaderNodeFloatOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR));7475add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), { VisualShaderNodeIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7476add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Sums two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7477add_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));7478add_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));7479add_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));7480add_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));7481add_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));7482add_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));7483add_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));7484add_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));7485add_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));7486add_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));7487add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), { VisualShaderNodeFloatOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR));7488add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), { VisualShaderNodeIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7489add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Divides two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7490add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR));7491add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), { VisualShaderNodeIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7492add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Multiplies two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7493add_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));7494add_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));7495add_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));7496add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), { VisualShaderNodeFloatOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR));7497add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), { VisualShaderNodeIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_INT));7498add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Subtracts two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));74997500add_options.push_back(AddOption("FloatConstant", "Scalar/Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7501add_options.push_back(AddOption("IntConstant", "Scalar/Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7502add_options.push_back(AddOption("UIntConstant", "Scalar/Variables", "VisualShaderNodeUIntConstant", TTR("Scalar unsigned integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));7503add_options.push_back(AddOption("FloatParameter", "Scalar/Variables", "VisualShaderNodeFloatParameter", TTR("Scalar floating-point parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7504add_options.push_back(AddOption("IntParameter", "Scalar/Variables", "VisualShaderNodeIntParameter", TTR("Scalar integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));7505add_options.push_back(AddOption("UIntParameter", "Scalar/Variables", "VisualShaderNodeUIntParameter", TTR("Scalar unsigned integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));75067507// SDF7508{7509add_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));7510add_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));7511add_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));7512add_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));7513add_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));7514}75157516// TEXTURES75177518add_options.push_back(AddOption("UVFunc", "Textures/Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));7519add_options.push_back(AddOption("UVPolarCoord", "Textures/Common", "VisualShaderNodeUVPolarCoord", TTR("Polar coordinates conversion applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));75207521cubemap_node_option_idx = add_options.size();7522add_options.push_back(AddOption("CubeMap", "Textures/Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7523curve_node_option_idx = add_options.size();7524add_options.push_back(AddOption("CurveTexture", "Textures/Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7525curve_xyz_node_option_idx = add_options.size();7526add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7527add_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));7528texture2d_node_option_idx = add_options.size();7529add_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));7530texture2d_node_option_idx = add_options.size();7531add_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));7532texture2d_node_option_idx = add_options.size();7533add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7534texture2d_array_node_option_idx = add_options.size();7535add_options.push_back(AddOption("Texture2DArray", "Textures/Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7536texture3d_node_option_idx = add_options.size();7537add_options.push_back(AddOption("Texture3D", "Textures/Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7538add_options.push_back(AddOption("UVPanning", "Textures/Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_PANNING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7539add_options.push_back(AddOption("UVScaling", "Textures/Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_SCALING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));75407541add_options.push_back(AddOption("CubeMapParameter", "Textures/Variables", "VisualShaderNodeCubemapParameter", TTR("Cubic texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));7542add_options.push_back(AddOption("Texture2DParameter", "Textures/Variables", "VisualShaderNodeTexture2DParameter", TTR("2D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));7543add_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));7544add_options.push_back(AddOption("Texture2DArrayParameter", "Textures/Variables", "VisualShaderNodeTexture2DArrayParameter", TTR("2D array of textures parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));7545add_options.push_back(AddOption("Texture3DParameter", "Textures/Variables", "VisualShaderNodeTexture3DParameter", TTR("3D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));75467547// TRANSFORM75487549add_options.push_back(AddOption("TransformFunc", "Transform/Common", "VisualShaderNodeTransformFunc", TTR("Transform function."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));7550add_options.push_back(AddOption("TransformOp", "Transform/Common", "VisualShaderNodeTransformOp", TTR("Transform operator."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));75517552add_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));7553add_options.push_back(AddOption("TransformCompose", "Transform/Composition", "VisualShaderNodeTransformCompose", TTR("Composes transform from four vectors."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));7554add_options.push_back(AddOption("TransformDecompose", "Transform/Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));75557556add_options.push_back(AddOption("Determinant", "Transform/Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7557add_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));7558add_options.push_back(AddOption("Inverse", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), { VisualShaderNodeTransformFunc::FUNC_INVERSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));7559add_options.push_back(AddOption("Transpose", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), { VisualShaderNodeTransformFunc::FUNC_TRANSPOSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));75607561add_options.push_back(AddOption("Add (+)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Sums two transforms."), { VisualShaderNodeTransformOp::OP_ADD }, VisualShaderNode::PORT_TYPE_TRANSFORM));7562add_options.push_back(AddOption("Divide (/)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Divides two transforms."), { VisualShaderNodeTransformOp::OP_A_DIV_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));7563add_options.push_back(AddOption("Multiply (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Multiplies two transforms."), { VisualShaderNodeTransformOp::OP_AxB }, VisualShaderNode::PORT_TYPE_TRANSFORM));7564add_options.push_back(AddOption("MultiplyComp (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Performs per-component multiplication of two transforms."), { VisualShaderNodeTransformOp::OP_AxB_COMP }, VisualShaderNode::PORT_TYPE_TRANSFORM));7565add_options.push_back(AddOption("Subtract (-)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Subtracts two transforms."), { VisualShaderNodeTransformOp::OP_A_MINUS_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));7566add_options.push_back(AddOption("TransformVectorMult (*)", "Transform/Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));75677568add_options.push_back(AddOption("TransformConstant", "Transform/Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));7569add_options.push_back(AddOption("TransformParameter", "Transform/Variables", "VisualShaderNodeTransformParameter", TTR("Transform parameter."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));75707571// UTILITY75727573add_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));7574add_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));7575add_options.push_back(AddOption("RandomRange", "Utility", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7576add_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));75777578// VECTOR75797580add_options.push_back(AddOption("VectorFunc", "Vector/Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7581add_options.push_back(AddOption("VectorOp", "Vector/Common", "VisualShaderNodeVectorOp", TTR("Vector operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7582add_options.push_back(AddOption("VectorCompose", "Vector/Common", "VisualShaderNodeVectorCompose", TTR("Composes vector from scalars.")));7583add_options.push_back(AddOption("VectorDecompose", "Vector/Common", "VisualShaderNodeVectorDecompose", TTR("Decomposes vector to scalars.")));75847585add_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));7586add_options.push_back(AddOption("Vector2Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 2D vector to two scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_2D }));7587add_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));7588add_options.push_back(AddOption("Vector3Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 3D vector to three scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_3D }));7589add_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));7590add_options.push_back(AddOption("Vector4Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 4D vector to four scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_4D }));75917592add_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));7593add_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));7594add_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));7595add_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));7596add_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));7597add_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));7598add_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));7599add_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));7600add_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));7601add_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));7602add_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));7603add_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));7604add_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));7605add_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));7606add_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));7607add_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));7608add_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));7609add_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));7610add_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));7611add_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));7612add_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));7613add_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));7614add_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));7615add_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));7616add_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));7617add_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));7618add_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));7619add_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));7620add_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));7621add_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));7622add_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));7623add_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));7624add_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));7625add_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));7626add_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));7627add_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));7628add_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));7629add_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));7630add_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));7631add_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));7632add_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));7633add_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));7634add_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));7635add_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));7636add_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));7637add_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));7638add_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));7639add_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));7640add_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));7641add_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));7642add_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));7643add_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));7644add_options.push_back(AddOption("Distance2D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));7645add_options.push_back(AddOption("Distance3D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));7646add_options.push_back(AddOption("Distance4D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));7647add_options.push_back(AddOption("Dot", "Vector/Functions", "VisualShaderNodeDotProduct", TTR("Calculates the dot product of two vectors."), {}, VisualShaderNode::PORT_TYPE_SCALAR));7648add_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));7649add_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));7650add_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));7651add_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));7652add_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));7653add_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));7654add_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));7655add_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));7656add_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));7657add_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));7658add_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));7659add_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));7660add_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));7661add_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));7662add_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));7663add_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));7664add_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));7665add_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));7666add_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));7667add_options.push_back(AddOption("Length2D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));7668add_options.push_back(AddOption("Length3D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));7669add_options.push_back(AddOption("Length4D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));7670add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7671add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7672add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7673add_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));7674add_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));7675add_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));7676add_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));7677add_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));7678add_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));7679add_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));7680add_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));7681add_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));7682add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7683add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7684add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7685add_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));7686add_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));7687add_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));7688add_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));7689add_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));7690add_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));7691add_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));7692add_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));7693add_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));7694add_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));7695add_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));7696add_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));7697add_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));7698add_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));7699add_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));7700add_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));7701add_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));7702add_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));7703add_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));7704add_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));7705add_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));7706add_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));7707add_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));7708add_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));7709add_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));7710add_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));7711add_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));7712add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), { VisualShaderNodeVectorRefract::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));7713add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), { VisualShaderNodeVectorRefract::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));7714add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), { VisualShaderNodeVectorRefract::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));7715add_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));7716add_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));7717add_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));7718add_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));7719add_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));7720add_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));7721add_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));7722add_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));7723add_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));7724add_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));7725add_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));7726add_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));7727add_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));7728add_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));7729add_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));7730add_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));7731add_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));7732add_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));7733add_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));7734add_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));7735add_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));7736add_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));7737add_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));7738add_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));7739add_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));7740add_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));7741add_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));7742add_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));7743add_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));7744add_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));7745add_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));7746add_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));7747add_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));7748add_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));7749add_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));7750add_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));7751add_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));7752add_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));7753add_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));7754add_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));7755add_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));7756add_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));7757add_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));7758add_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));7759add_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));7760add_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));7761add_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));7762add_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));7763add_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));7764add_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));7765add_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));7766add_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));7767add_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));77687769add_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));7770add_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));7771add_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));7772add_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));7773add_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));7774add_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));7775add_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));7776add_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));7777add_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));7778add_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));7779add_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));7780add_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));7781add_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));7782add_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));7783add_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));77847785add_options.push_back(AddOption("Vector2Constant", "Vector/Variables", "VisualShaderNodeVec2Constant", TTR("2D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));7786add_options.push_back(AddOption("Vector2Parameter", "Vector/Variables", "VisualShaderNodeVec2Parameter", TTR("2D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));7787add_options.push_back(AddOption("Vector3Constant", "Vector/Variables", "VisualShaderNodeVec3Constant", TTR("3D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7788add_options.push_back(AddOption("Vector3Parameter", "Vector/Variables", "VisualShaderNodeVec3Parameter", TTR("3D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));7789add_options.push_back(AddOption("Vector4Constant", "Vector/Variables", "VisualShaderNodeVec4Constant", TTR("4D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));7790add_options.push_back(AddOption("Vector4Parameter", "Vector/Variables", "VisualShaderNodeVec4Parameter", TTR("4D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));77917792// SPECIAL7793add_options.push_back(AddOption("Frame", "Special", "VisualShaderNodeFrame", TTR("A rectangular area with a description string for better graph organization.")));7794add_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.")));7795add_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.")));7796add_options.push_back(AddOption("ParameterRef", "Special", "VisualShaderNodeParameterRef", TTR("A reference to an existing parameter.")));7797add_options.push_back(AddOption("VaryingGetter", "Special", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));7798add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));7799add_options.push_back(AddOption("VaryingGetter", "Special", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));7800add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));7801add_options.push_back(AddOption("Reroute", "Special", "VisualShaderNodeReroute", TTR("Reroute connections freely, can be used to connect multiple input ports to single output port.")));78027803custom_node_option_idx = add_options.size();78047805/////////////////////////////////////////////////////////////////////78067807Ref<VisualShaderNodePluginDefault> default_plugin;7808default_plugin.instantiate();7809default_plugin->set_editor(this);7810add_plugin(default_plugin);78117812graph_plugin.instantiate();7813graph_plugin->set_editor(this);78147815property_editor_popup = memnew(PopupPanel);7816property_editor_popup->set_min_size(Size2(360, 0) * EDSCALE);7817add_child(property_editor_popup);78187819edited_property_holder.instantiate();78207821panning_debounce_timer = memnew(Timer);7822panning_debounce_timer->set_one_shot(true);7823panning_debounce_timer->set_wait_time(1.0);7824panning_debounce_timer->connect("timeout", callable_mp(this, &VisualShaderEditor::save_editor_layout));7825add_child(panning_debounce_timer);7826}78277828VisualShaderEditor::~VisualShaderEditor() {7829save_editor_layout();7830}78317832class VisualShaderNodePluginInputEditor : public OptionButton {7833GDCLASS(VisualShaderNodePluginInputEditor, OptionButton);78347835VisualShaderEditor *editor = nullptr;7836Ref<VisualShaderNodeInput> input;78377838public:7839void _notification(int p_what) {7840switch (p_what) {7841case NOTIFICATION_READY: {7842connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected));7843} break;7844}7845}78467847void _item_selected(int p_item) {7848editor->call_deferred(SNAME("_input_select_item"), input, get_item_metadata(p_item));7849}78507851void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeInput> &p_input) {7852set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);78537854editor = p_editor;7855input = p_input;78567857Ref<Texture2D> type_icon[] = {7858EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),7859EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),7860EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),7861EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),7862EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),7863EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),7864EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),7865EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),7866EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),7867};78687869add_item(TTR("[None]"));7870set_item_metadata(-1, "[None]");78717872int to_select = -1;7873for (int i = 0; i < input->get_input_index_count(); i++) {7874if (input->get_input_name() == input->get_input_index_name(i)) {7875to_select = i + 1;7876}7877add_icon_item(type_icon[input->get_input_index_type(i)], input->get_input_index_name(i));7878set_item_metadata(-1, input->get_input_index_name(i));7879}78807881if (to_select >= 0) {7882select(to_select);7883}7884}7885};78867887////////////////78887889class VisualShaderNodePluginVaryingEditor : public OptionButton {7890GDCLASS(VisualShaderNodePluginVaryingEditor, OptionButton);78917892VisualShaderEditor *editor = nullptr;7893Ref<VisualShaderNodeVarying> varying;78947895public:7896void _notification(int p_what) {7897if (p_what == NOTIFICATION_READY) {7898connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderNodePluginVaryingEditor::_item_selected));7899}7900}79017902void _item_selected(int p_item) {7903editor->call_deferred(SNAME("_varying_select_item"), varying, get_item_metadata(p_item));7904}79057906void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeVarying> &p_varying, VisualShader::Type p_type) {7907set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);79087909editor = p_editor;7910varying = p_varying;79117912Ref<Texture2D> type_icon[] = {7913EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),7914EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),7915EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),7916EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),7917EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),7918EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),7919EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),7920EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),7921};79227923bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();79247925add_item(TTR("[None]"));7926set_item_metadata(-1, "[None]");79277928int to_select = -1;7929for (int i = 0, j = 0; i < varying->get_varyings_count(); i++) {7930VisualShader::VaryingMode mode = varying->get_varying_mode_by_index(i);7931if (is_getter) {7932if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {7933if (p_type != VisualShader::TYPE_LIGHT) {7934j++;7935continue;7936}7937} else {7938if (p_type != VisualShader::TYPE_FRAGMENT && p_type != VisualShader::TYPE_LIGHT) {7939j++;7940continue;7941}7942}7943} else {7944if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {7945if (p_type != VisualShader::TYPE_FRAGMENT) {7946j++;7947continue;7948}7949} else {7950if (p_type != VisualShader::TYPE_VERTEX) {7951j++;7952continue;7953}7954}7955}7956if (varying->get_varying_name() == varying->get_varying_name_by_index(i)) {7957to_select = i - j + 1;7958}7959add_icon_item(type_icon[varying->get_varying_type_by_index(i)], varying->get_varying_name_by_index(i));7960set_item_metadata(-1, varying->get_varying_name_by_index(i));7961}79627963if (to_select >= 0) {7964select(to_select);7965}7966}7967};79687969////////////////79707971class VisualShaderNodePluginParameterRefEditor : public OptionButton {7972GDCLASS(VisualShaderNodePluginParameterRefEditor, OptionButton);79737974VisualShaderEditor *editor = nullptr;7975Ref<VisualShaderNodeParameterRef> parameter_ref;79767977public:7978void _notification(int p_what) {7979switch (p_what) {7980case NOTIFICATION_READY: {7981connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderNodePluginParameterRefEditor::_item_selected));7982} break;7983}7984}79857986void _item_selected(int p_item) {7987editor->call_deferred(SNAME("_parameter_ref_select_item"), parameter_ref, get_item_metadata(p_item));7988}79897990void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeParameterRef> &p_parameter_ref) {7991set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);79927993editor = p_editor;7994parameter_ref = p_parameter_ref;79957996Ref<Texture2D> type_icon[] = {7997EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),7998EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),7999EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),8000EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),8001EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),8002EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),8003EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),8004EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),8005EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Color"), EditorStringName(EditorIcons)),8006EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),8007};80088009add_item(TTR("[None]"));8010set_item_metadata(-1, "[None]");80118012int to_select = -1;8013for (int i = 0; i < p_parameter_ref->get_parameters_count(); i++) {8014if (p_parameter_ref->get_parameter_name() == p_parameter_ref->get_parameter_name_by_index(i)) {8015to_select = i + 1;8016}8017add_icon_item(type_icon[p_parameter_ref->get_parameter_type_by_index(i)], p_parameter_ref->get_parameter_name_by_index(i));8018set_item_metadata(-1, p_parameter_ref->get_parameter_name_by_index(i));8019}80208021if (to_select >= 0) {8022select(to_select);8023}8024}8025};80268027////////////////80288029class VisualShaderNodePluginDefaultEditor : public VBoxContainer {8030GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer);8031VisualShaderEditor *editor = nullptr;8032Ref<Resource> parent_resource;8033int node_id = 0;8034VisualShader::Type shader_type;80358036public:8037void _property_changed(const String &p_property, const Variant &p_value, const String &p_field = "", bool p_changing = false) {8038if (p_changing) {8039return;8040}80418042EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();80438044updating = true;8045undo_redo->create_action(vformat(TTR("Edit Visual Property: %s"), p_property), UndoRedo::MERGE_ENDS);8046undo_redo->add_do_property(node.ptr(), p_property, p_value);8047undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property));80488049Ref<VisualShaderNode> vsnode = editor->get_visual_shader()->get_node(shader_type, node_id);8050ERR_FAIL_COND(vsnode.is_null());80518052// Check for invalid connections due to removed ports.8053// We need to know the new state of the node to generate the proper undo/redo instructions.8054// Quite hacky but the best way I could come up with for now.8055Ref<VisualShaderNode> vsnode_new = vsnode->duplicate();8056vsnode_new->set(p_property, p_value);8057const int input_port_count = vsnode_new->get_input_port_count();8058const int output_port_count = vsnode_new->get_expanded_output_port_count();80598060List<VisualShader::Connection> conns;8061editor->get_visual_shader()->get_node_connections(shader_type, &conns);8062VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();8063bool undo_node_already_updated = false;8064for (const VisualShader::Connection &c : conns) {8065if ((c.from_node == node_id && c.from_port >= output_port_count) || (c.to_node == node_id && c.to_port >= input_port_count)) {8066undo_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);8067undo_redo->add_do_method(graph_plugin, "disconnect_nodes", shader_type, c.from_node, c.from_port, c.to_node, c.to_port);8068// We need to update the node before reconnecting to avoid accessing a non-existing port.8069undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);8070undo_node_already_updated = true;8071undo_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);8072undo_redo->add_undo_method(graph_plugin, "connect_nodes", shader_type, c.from_node, c.from_port, c.to_node, c.to_port);8073}8074}80758076if (p_value.get_type() == Variant::OBJECT) {8077Ref<Resource> prev_res = vsnode->get(p_property);8078Ref<Resource> curr_res = p_value;80798080if (curr_res.is_null()) {8081undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());8082} else {8083undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)curr_res.ptr());8084}8085if (prev_res.is_valid()) {8086undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)prev_res.ptr());8087} else {8088undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());8089}8090}8091if (p_property != "constant") {8092if (graph_plugin) {8093undo_redo->add_do_method(editor, "_update_next_previews", node_id);8094undo_redo->add_undo_method(editor, "_update_next_previews", node_id);8095undo_redo->add_do_method(graph_plugin, "update_node_deferred", shader_type, node_id);8096if (!undo_node_already_updated) {8097undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);8098}8099}8100}81018102undo_redo->commit_action();81038104updating = false;8105}81068107void _node_changed() {8108if (updating) {8109return;8110}8111for (int i = 0; i < properties.size(); i++) {8112properties[i]->update_property();8113}8114}81158116void _resource_selected(const String &p_path, Ref<Resource> p_resource) {8117_open_inspector(p_resource);8118}81198120void _open_inspector(Ref<Resource> p_resource) {8121InspectorDock::get_inspector_singleton()->edit(p_resource.ptr());8122}81238124bool updating = false;8125Ref<VisualShaderNode> node;8126Vector<EditorProperty *> properties;8127Vector<Label *> prop_names;81288129void _show_prop_names(bool p_show) {8130for (int i = 0; i < prop_names.size(); i++) {8131prop_names[i]->set_visible(p_show);8132}8133}81348135void 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) {8136editor = p_editor;8137parent_resource = p_parent_resource;8138updating = false;8139node = p_node;8140properties = p_properties;81418142node_id = (int)p_node->get_meta("id");8143shader_type = VisualShader::Type((int)p_node->get_meta("shader_type"));81448145for (int i = 0; i < p_properties.size(); i++) {8146HBoxContainer *hbox = memnew(HBoxContainer);8147hbox->set_h_size_flags(SIZE_EXPAND_FILL);8148add_child(hbox);81498150Label *prop_name = memnew(Label);8151prop_name->set_focus_mode(Control::FOCUS_ACCESSIBILITY);8152String prop_name_str = p_names[i];8153if (p_overrided_names.has(p_names[i])) {8154prop_name_str = p_overrided_names[p_names[i]] + ":";8155} else {8156prop_name_str = prop_name_str.capitalize() + ":";8157}8158prop_name->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch.8159prop_name->set_text(prop_name_str);8160prop_name->set_visible(false);8161hbox->add_child(prop_name);8162prop_names.push_back(prop_name);81638164p_properties[i]->set_h_size_flags(SIZE_EXPAND_FILL);8165hbox->add_child(p_properties[i]);81668167bool res_prop = Object::cast_to<EditorPropertyResource>(p_properties[i]);8168if (res_prop) {8169p_properties[i]->connect("resource_selected", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_resource_selected));8170}81718172properties[i]->connect("property_changed", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_property_changed));8173properties[i]->set_object_and_property(node.ptr(), p_names[i]);8174properties[i]->update_property();8175properties[i]->set_name_split_ratio(0);8176}8177node->connect_changed(callable_mp(this, &VisualShaderNodePluginDefaultEditor::_node_changed));8178}81798180static void _bind_methods() {8181ClassDB::bind_method("_open_inspector", &VisualShaderNodePluginDefaultEditor::_open_inspector); // Used by UndoRedo.8182ClassDB::bind_method("_show_prop_names", &VisualShaderNodePluginDefaultEditor::_show_prop_names); // Used with call_deferred.8183}8184};81858186Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {8187Ref<VisualShader> p_shader = Ref<VisualShader>(p_parent_resource.ptr());81888189if (p_shader.is_valid() && (p_node->is_class("VisualShaderNodeVaryingGetter") || p_node->is_class("VisualShaderNodeVaryingSetter"))) {8190VisualShaderNodePluginVaryingEditor *editor = memnew(VisualShaderNodePluginVaryingEditor);8191editor->setup(vseditor, p_node, vseditor->get_current_shader_type());8192return editor;8193}81948195if (p_node->is_class("VisualShaderNodeParameterRef")) {8196VisualShaderNodePluginParameterRefEditor *editor = memnew(VisualShaderNodePluginParameterRefEditor);8197editor->setup(vseditor, p_node);8198return editor;8199}82008201if (p_node->is_class("VisualShaderNodeInput")) {8202VisualShaderNodePluginInputEditor *editor = memnew(VisualShaderNodePluginInputEditor);8203editor->setup(vseditor, p_node);8204return editor;8205}82068207Vector<StringName> properties = p_node->get_editable_properties();8208if (properties.is_empty()) {8209return nullptr;8210}82118212List<PropertyInfo> props;8213p_node->get_property_list(&props);82148215Vector<PropertyInfo> pinfo;82168217for (const PropertyInfo &E : props) {8218for (int i = 0; i < properties.size(); i++) {8219if (E.name == String(properties[i])) {8220pinfo.push_back(E);8221}8222}8223}82248225if (pinfo.is_empty()) {8226return nullptr;8227}82288229properties.clear();82308231Ref<VisualShaderNode> node = p_node;8232Vector<EditorProperty *> editors;82338234for (int i = 0; i < pinfo.size(); i++) {8235EditorProperty *prop = EditorInspector::instantiate_property_editor(node.ptr(), pinfo[i].type, pinfo[i].name, pinfo[i].hint, pinfo[i].hint_string, pinfo[i].usage);8236if (!prop) {8237return nullptr;8238}82398240if (Object::cast_to<EditorPropertyResource>(prop)) {8241Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false);8242prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));8243} else if (Object::cast_to<EditorPropertyTransform3D>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) {8244prop->set_custom_minimum_size(Size2(250 * EDSCALE, 0));8245} else if (Object::cast_to<EditorPropertyVector4>(prop)) {8246prop->set_custom_minimum_size(Size2(320 * EDSCALE, 0));8247} else if (Object::cast_to<EditorPropertyFloat>(prop)) {8248prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));8249} else if (Object::cast_to<EditorPropertyEnum>(prop)) {8250prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));8251Object::cast_to<EditorPropertyEnum>(prop)->set_option_button_clip(false);8252} else if (Object::cast_to<EditorPropertyColor>(prop)) {8253Object::cast_to<EditorPropertyColor>(prop)->set_live_changes_enabled(false);8254}82558256editors.push_back(prop);8257properties.push_back(pinfo[i].name);8258}8259VisualShaderNodePluginDefaultEditor *editor = memnew(VisualShaderNodePluginDefaultEditor);8260editor->setup(vseditor, p_parent_resource, editors, properties, p_node->get_editable_properties_names(), p_node);8261return editor;8262}82638264void EditorPropertyVisualShaderMode::_option_selected(int p_which) {8265Ref<VisualShader> visual_shader(Object::cast_to<VisualShader>(get_edited_object()));8266if (visual_shader->get_mode() == p_which) {8267return;8268}82698270ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_editor_data().get_editor_by_name("Shader"));8271if (!shader_editor) {8272return;8273}8274VisualShaderEditor *editor = Object::cast_to<VisualShaderEditor>(shader_editor->get_shader_editor(visual_shader));8275if (!editor) {8276return;8277}82788279EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();8280undo_redo->create_action(TTR("Visual Shader Mode Changed"));8281//do is easy8282undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);8283undo_redo->add_undo_method(visual_shader.ptr(), "set_mode", visual_shader->get_mode());82848285undo_redo->add_do_method(editor, "_set_mode", p_which);8286undo_redo->add_undo_method(editor, "_set_mode", visual_shader->get_mode());82878288//now undo is hell82898290//1. restore connections to output8291for (int i = 0; i < VisualShader::TYPE_MAX; i++) {8292VisualShader::Type type = VisualShader::Type(i);8293List<VisualShader::Connection> conns;8294visual_shader->get_node_connections(type, &conns);8295for (const VisualShader::Connection &E : conns) {8296if (E.to_node == VisualShader::NODE_ID_OUTPUT) {8297undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);8298}8299}8300}8301//2. restore input indices8302for (int i = 0; i < VisualShader::TYPE_MAX; i++) {8303VisualShader::Type type = VisualShader::Type(i);8304Vector<int> nodes = visual_shader->get_node_list(type);8305for (int j = 0; j < nodes.size(); j++) {8306Ref<VisualShaderNodeInput> input = visual_shader->get_node(type, nodes[j]);8307if (input.is_null()) {8308continue;8309}83108311undo_redo->add_undo_method(input.ptr(), "set_input_name", input->get_input_name());8312}8313}83148315//3. restore enums and flags8316List<PropertyInfo> props;8317visual_shader->get_property_list(&props);83188319for (const PropertyInfo &E : props) {8320if (E.name.begins_with("flags/") || E.name.begins_with("modes/")) {8321undo_redo->add_undo_property(visual_shader.ptr(), E.name, visual_shader->get(E.name));8322}8323}83248325//4. delete varyings (if needed)8326if (p_which == VisualShader::MODE_PARTICLES || p_which == VisualShader::MODE_SKY || p_which == VisualShader::MODE_FOG || p_which == VisualShader::MODE_TEXTURE_BLIT) {8327int var_count = visual_shader->get_varyings_count();83288329if (var_count > 0) {8330for (int i = 0; i < var_count; i++) {8331const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);8332undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", var->name);8333undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", var->name, var->mode, var->type);8334}83358336undo_redo->add_do_method(editor, "_update_varyings");8337undo_redo->add_undo_method(editor, "_update_varyings");8338}8339}83408341undo_redo->add_do_method(editor, "_update_nodes");8342undo_redo->add_undo_method(editor, "_update_nodes");83438344undo_redo->add_do_method(editor, "_update_graph");8345undo_redo->add_undo_method(editor, "_update_graph");83468347undo_redo->commit_action();8348}83498350void EditorPropertyVisualShaderMode::update_property() {8351int which = get_edited_property_value();8352options->select(which);8353}83548355void EditorPropertyVisualShaderMode::setup(const Vector<String> &p_options) {8356for (int i = 0; i < p_options.size(); i++) {8357options->add_item(p_options[i], i);8358}8359}83608361void EditorPropertyVisualShaderMode::set_option_button_clip(bool p_enable) {8362options->set_clip_text(p_enable);8363}83648365EditorPropertyVisualShaderMode::EditorPropertyVisualShaderMode() {8366options = memnew(OptionButton);8367options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);8368options->set_clip_text(true);8369add_child(options);8370add_focusable(options);8371options->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyVisualShaderMode::_option_selected));8372}83738374bool EditorInspectorVisualShaderModePlugin::can_handle(Object *p_object) {8375return true; // Can handle everything.8376}83778378bool 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) {8379if (p_path == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) {8380EditorPropertyVisualShaderMode *mode_editor = memnew(EditorPropertyVisualShaderMode);8381Vector<String> options = p_hint_text.split(",");8382mode_editor->setup(options);8383add_property_editor(p_path, mode_editor);83848385return true;8386}83878388return false;8389}83908391//////////////////////////////////83928393void VisualShaderNodePortPreview::_shader_changed() {8394if (!is_valid || shader.is_null()) {8395return;8396}83978398Vector<VisualShader::DefaultTextureParam> default_textures;8399String shader_code = shader->generate_preview_shader(type, node, port, default_textures);84008401Ref<Shader> preview_shader;8402preview_shader.instantiate();8403preview_shader->set_code(shader_code);8404for (int i = 0; i < default_textures.size(); i++) {8405int j = 0;8406for (List<Ref<Texture>>::ConstIterator itr = default_textures[i].params.begin(); itr != default_textures[i].params.end(); ++itr, ++j) {8407preview_shader->set_default_texture_parameter(default_textures[i].name, *itr, j);8408}8409}84108411Ref<ShaderMaterial> mat;8412mat.instantiate();8413mat->set_shader(preview_shader);84148415if (preview_mat.is_valid() && preview_mat->get_shader().is_valid()) {8416List<PropertyInfo> params;8417preview_mat->get_shader()->get_shader_uniform_list(¶ms);8418for (const PropertyInfo &E : params) {8419mat->set_shader_parameter(E.name, preview_mat->get_shader_parameter(E.name));8420}8421}84228423set_material(mat);8424}84258426void 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) {8427if (p_has_transparency) {8428checkerboard = memnew(TextureRect);8429checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE);8430checkerboard->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);8431checkerboard->set_draw_behind_parent(true);8432add_child(checkerboard);8433}84348435set_mouse_filter(MOUSE_FILTER_PASS);8436shader = p_shader;8437shader->connect_changed(callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);8438preview_mat = p_preview_material;8439type = p_type;8440port = p_port;8441node = p_node;8442is_valid = p_is_valid;8443queue_redraw();8444_shader_changed();8445}84468447Size2 VisualShaderNodePortPreview::get_minimum_size() const {8448int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size");8449return Size2(port_preview_size, port_preview_size) * EDSCALE;8450}84518452void VisualShaderNodePortPreview::_notification(int p_what) {8453switch (p_what) {8454case NOTIFICATION_THEME_CHANGED: {8455if (checkerboard != nullptr) {8456checkerboard->set_texture(get_theme_icon(SNAME("GuiMiniCheckerboard"), EditorStringName(EditorIcons)));8457}8458} break;8459case NOTIFICATION_DRAW: {8460Vector<Vector2> points = {8461Vector2(),8462Vector2(get_size().width, 0),8463get_size(),8464Vector2(0, get_size().height)8465};84668467Vector<Vector2> uvs = {8468Vector2(0, 0),8469Vector2(1, 0),8470Vector2(1, 1),8471Vector2(0, 1)8472};84738474if (is_valid) {8475Vector<Color> colors = {8476Color(1, 1, 1, 1),8477Color(1, 1, 1, 1),8478Color(1, 1, 1, 1),8479Color(1, 1, 1, 1)8480};8481draw_primitive(points, colors, uvs);8482} else {8483Vector<Color> colors = {8484Color(0, 0, 0, 1),8485Color(0, 0, 0, 1),8486Color(0, 0, 0, 1),8487Color(0, 0, 0, 1)8488};8489draw_primitive(points, colors, uvs);8490}84918492} break;8493}8494}84958496//////////////////////////////////84978498String VisualShaderConversionPlugin::converts_to() const {8499return "Shader";8500}85018502bool VisualShaderConversionPlugin::handles(const Ref<Resource> &p_resource) const {8503Ref<VisualShader> vshader = p_resource;8504return vshader.is_valid();8505}85068507Ref<Resource> VisualShaderConversionPlugin::convert(const Ref<Resource> &p_resource) const {8508Ref<VisualShader> vshader = p_resource;8509ERR_FAIL_COND_V(vshader.is_null(), Ref<Resource>());8510int embed = vshader->has_node_embeds();85118512EditorToaster *toast = EditorToaster::get_singleton();8513if (toast == nullptr) {8514ERR_FAIL_COND_V_MSG(embed == 2, Ref<Resource>(), "Cannot convert VisualShader to GDShader because VisualShader has embedded subresources.");8515if (embed == 1) {8516WARN_PRINT("Visual Shader conversion cannot convert external dependencies. Resource references from Nodes will have to be rebound as ShaderParameters on a Material.");8517}8518} else if (embed == 2) {8519toast->popup_str(TTR("Cannot convert VisualShader to GDShader because VisualShader has embedded subresources."), EditorToaster::SEVERITY_ERROR);8520return Ref<Resource>();8521} else if (embed == 1) {8522toast->popup_str(TTR("Visual Shader conversion cannot convert external dependencies. Resource references from Nodes will have to be rebound as ShaderParameters on a Material."), EditorToaster::SEVERITY_WARNING);8523}85248525Ref<Shader> shader;8526shader.instantiate();85278528String code = vshader->get_code();8529shader->set_code(code);85308531return shader;8532}853385348535