1/**************************************************************************/
2/* visual_shader_editor_plugin.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "visual_shader_editor_plugin.h"
32
33#include "core/config/project_settings.h"
34#include "core/io/resource_loader.h"
35#include "core/math/math_defs.h"
36#include "core/os/keyboard.h"
37#include "editor/editor_node.h"
38#include "editor/editor_properties.h"
39#include "editor/editor_properties_vector.h"
40#include "editor/editor_scale.h"
41#include "editor/editor_settings.h"
42#include "editor/editor_string_names.h"
43#include "editor/editor_undo_redo_manager.h"
44#include "editor/filesystem_dock.h"
45#include "editor/inspector_dock.h"
46#include "editor/plugins/curve_editor_plugin.h"
47#include "editor/plugins/shader_editor_plugin.h"
48#include "scene/gui/button.h"
49#include "scene/gui/check_box.h"
50#include "scene/gui/code_edit.h"
51#include "scene/gui/graph_edit.h"
52#include "scene/gui/menu_button.h"
53#include "scene/gui/option_button.h"
54#include "scene/gui/popup.h"
55#include "scene/gui/rich_text_label.h"
56#include "scene/gui/separator.h"
57#include "scene/gui/tree.h"
58#include "scene/gui/view_panner.h"
59#include "scene/main/window.h"
60#include "scene/resources/curve_texture.h"
61#include "scene/resources/image_texture.h"
62#include "scene/resources/style_box_flat.h"
63#include "scene/resources/visual_shader_nodes.h"
64#include "scene/resources/visual_shader_particle_nodes.h"
65#include "servers/display_server.h"
66#include "servers/rendering/shader_types.h"
67
68struct FloatConstantDef {
69 String name;
70 float value = 0;
71 String desc;
72};
73
74static FloatConstantDef float_constant_defs[] = {
75 { "E", Math_E, TTR("E constant (2.718282). Represents the base of the natural logarithm.") },
76 { "Epsilon", CMP_EPSILON, TTR("Epsilon constant (0.00001). Smallest possible scalar number.") },
77 { "Phi", 1.618034f, TTR("Phi constant (1.618034). Golden ratio.") },
78 { "Pi/4", Math_PI / 4, TTR("Pi/4 constant (0.785398) or 45 degrees.") },
79 { "Pi/2", Math_PI / 2, TTR("Pi/2 constant (1.570796) or 90 degrees.") },
80 { "Pi", Math_PI, TTR("Pi constant (3.141593) or 180 degrees.") },
81 { "Tau", Math_TAU, TTR("Tau constant (6.283185) or 360 degrees.") },
82 { "Sqrt2", Math_SQRT2, TTR("Sqrt2 constant (1.414214). Square root of 2.") }
83};
84
85const int MAX_FLOAT_CONST_DEFS = sizeof(float_constant_defs) / sizeof(FloatConstantDef);
86
87///////////////////
88
89void VisualShaderNodePlugin::set_editor(VisualShaderEditor *p_editor) {
90 vseditor = p_editor;
91}
92
93Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {
94 Object *ret = nullptr;
95 GDVIRTUAL_CALL(_create_editor, p_parent_resource, p_node, ret);
96 return Object::cast_to<Control>(ret);
97}
98
99void VisualShaderNodePlugin::_bind_methods() {
100 GDVIRTUAL_BIND(_create_editor, "parent_resource", "visual_shader_node");
101}
102
103///////////////////
104
105VisualShaderGraphPlugin::VisualShaderGraphPlugin() {
106}
107
108void VisualShaderGraphPlugin::_bind_methods() {
109 ClassDB::bind_method("add_node", &VisualShaderGraphPlugin::add_node);
110 ClassDB::bind_method("remove_node", &VisualShaderGraphPlugin::remove_node);
111 ClassDB::bind_method("connect_nodes", &VisualShaderGraphPlugin::connect_nodes);
112 ClassDB::bind_method("disconnect_nodes", &VisualShaderGraphPlugin::disconnect_nodes);
113 ClassDB::bind_method("set_node_position", &VisualShaderGraphPlugin::set_node_position);
114 ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);
115 ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);
116 ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);
117 ClassDB::bind_method("set_parameter_name", &VisualShaderGraphPlugin::set_parameter_name);
118 ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression);
119 ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve);
120 ClassDB::bind_method("update_curve_xyz", &VisualShaderGraphPlugin::update_curve_xyz);
121}
122
123void VisualShaderGraphPlugin::set_editor(VisualShaderEditor *p_editor) {
124 editor = p_editor;
125}
126
127void VisualShaderGraphPlugin::register_shader(VisualShader *p_shader) {
128 visual_shader = Ref<VisualShader>(p_shader);
129}
130
131void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connection> &p_connections) {
132 connections = p_connections;
133}
134
135void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid) {
136 if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {
137 Link &link = links[p_node_id];
138
139 for (const KeyValue<int, Port> &E : link.output_ports) {
140 if (E.value.preview_button != nullptr) {
141 E.value.preview_button->set_pressed(false);
142 }
143 }
144 bool is_dirty = link.preview_pos < 0;
145
146 if (!is_dirty && link.preview_visible && link.preview_box != nullptr) {
147 link.graph_element->remove_child(link.preview_box);
148 memdelete(link.preview_box);
149 link.preview_box = nullptr;
150 link.graph_element->reset_size();
151 link.preview_visible = false;
152 }
153
154 if (p_port_id != -1 && link.output_ports[p_port_id].preview_button != nullptr) {
155 if (is_dirty) {
156 link.preview_pos = link.graph_element->get_child_count();
157 }
158
159 VBoxContainer *vbox = memnew(VBoxContainer);
160 link.graph_element->add_child(vbox);
161 link.graph_element->move_child(vbox, link.preview_pos);
162
163 GraphNode *graph_node = Object::cast_to<GraphNode>(link.graph_element);
164 if (graph_node) {
165 graph_node->set_slot_draw_stylebox(vbox->get_index(false), false);
166 }
167
168 Control *offset = memnew(Control);
169 offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
170 vbox->add_child(offset);
171
172 VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);
173 port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id, p_is_valid);
174 port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
175 vbox->add_child(port_preview);
176 link.preview_visible = true;
177 link.preview_box = vbox;
178 link.output_ports[p_port_id].preview_button->set_pressed(true);
179 }
180 }
181}
182
183void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, int p_node_id) {
184 call_deferred(SNAME("update_node"), p_type, p_node_id);
185}
186
187void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) {
188 if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) {
189 return;
190 }
191 remove_node(p_type, p_node_id, true);
192 add_node(p_type, p_node_id, true);
193}
194
195void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value) {
196 if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) {
197 return;
198 }
199
200 Button *button = links[p_node_id].input_ports[p_port_id].default_input_button;
201
202 switch (p_value.get_type()) {
203 case Variant::COLOR: {
204 button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);
205
206 Callable ce = callable_mp(editor, &VisualShaderEditor::_draw_color_over_button);
207 if (!button->is_connected("draw", ce)) {
208 button->connect("draw", ce.bind(button, p_value));
209 }
210 } break;
211 case Variant::BOOL: {
212 button->set_text(((bool)p_value) ? "true" : "false");
213 } break;
214 case Variant::INT:
215 case Variant::FLOAT: {
216 button->set_text(String::num(p_value, 4));
217 } break;
218 case Variant::VECTOR2: {
219 Vector2 v = p_value;
220 button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3));
221 } break;
222 case Variant::VECTOR3: {
223 Vector3 v = p_value;
224 button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3));
225 } break;
226 case Variant::QUATERNION: {
227 Quaternion v = p_value;
228 button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3) + "," + String::num(v.w, 3));
229 } break;
230 default: {
231 }
232 }
233}
234
235void VisualShaderGraphPlugin::set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {
236 if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].parameter_name != nullptr) {
237 links[p_node_id].parameter_name->set_text(p_name);
238 }
239}
240
241void VisualShaderGraphPlugin::update_curve(int p_node_id) {
242 if (links.has(p_node_id) && links[p_node_id].curve_editors[0]) {
243 Ref<VisualShaderNodeCurveTexture> tex = Object::cast_to<VisualShaderNodeCurveTexture>(links[p_node_id].visual_node);
244 ERR_FAIL_COND(!tex.is_valid());
245
246 if (tex->get_texture().is_valid()) {
247 links[p_node_id].curve_editors[0]->set_curve(tex->get_texture()->get_curve());
248 }
249 tex->emit_changed();
250 }
251}
252
253void VisualShaderGraphPlugin::update_curve_xyz(int p_node_id) {
254 if (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]) {
255 Ref<VisualShaderNodeCurveXYZTexture> tex = Object::cast_to<VisualShaderNodeCurveXYZTexture>(links[p_node_id].visual_node);
256 ERR_FAIL_COND(!tex.is_valid());
257
258 if (tex->get_texture().is_valid()) {
259 links[p_node_id].curve_editors[0]->set_curve(tex->get_texture()->get_curve_x());
260 links[p_node_id].curve_editors[1]->set_curve(tex->get_texture()->get_curve_y());
261 links[p_node_id].curve_editors[2]->set_curve(tex->get_texture()->get_curve_z());
262 }
263 tex->emit_changed();
264 }
265}
266
267int VisualShaderGraphPlugin::get_constant_index(float p_constant) const {
268 for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {
269 if (Math::is_equal_approx(p_constant, float_constant_defs[i].value)) {
270 return i + 1;
271 }
272 }
273 return 0;
274}
275
276void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression) {
277 if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id) || !links[p_node_id].expression_edit) {
278 return;
279 }
280 links[p_node_id].expression_edit->set_text(p_expression);
281}
282
283Ref<Script> VisualShaderGraphPlugin::get_node_script(int p_node_id) const {
284 if (!links.has(p_node_id)) {
285 return Ref<Script>();
286 }
287
288 Ref<VisualShaderNodeCustom> custom = Ref<VisualShaderNodeCustom>(links[p_node_id].visual_node);
289 if (custom.is_valid()) {
290 return custom->get_script();
291 }
292
293 return Ref<Script>();
294}
295
296void VisualShaderGraphPlugin::update_node_size(int p_node_id) {
297 if (!links.has(p_node_id)) {
298 return;
299 }
300 links[p_node_id].graph_element->reset_size();
301}
302
303void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) {
304 links[p_node_id].input_ports.insert(p_port_id, { p_button });
305}
306
307void VisualShaderGraphPlugin::register_expression_edit(int p_node_id, CodeEdit *p_expression_edit) {
308 links[p_node_id].expression_edit = p_expression_edit;
309}
310
311void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor) {
312 links[p_node_id].curve_editors[p_index] = p_curve_editor;
313}
314
315void VisualShaderGraphPlugin::update_parameter_refs() {
316 for (KeyValue<int, Link> &E : links) {
317 VisualShaderNodeParameterRef *ref = Object::cast_to<VisualShaderNodeParameterRef>(E.value.visual_node);
318 if (ref) {
319 remove_node(E.value.type, E.key, true);
320 add_node(E.value.type, E.key, true);
321 }
322 }
323}
324
325VisualShader::Type VisualShaderGraphPlugin::get_shader_type() const {
326 return visual_shader->get_shader_type();
327}
328
329void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) {
330 if (visual_shader->get_shader_type() == p_type && links.has(p_id)) {
331 links[p_id].graph_element->set_position_offset(p_position);
332 }
333}
334
335bool VisualShaderGraphPlugin::is_preview_visible(int p_id) const {
336 return links[p_id].preview_visible;
337}
338
339void VisualShaderGraphPlugin::clear_links() {
340 links.clear();
341}
342
343void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphElement *p_graph_element) {
344 links.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 } });
345}
346
347void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) {
348 links[p_node_id].output_ports.insert(p_port, { p_button });
349}
350
351void VisualShaderGraphPlugin::register_parameter_name(int p_node_id, LineEdit *p_parameter_name) {
352 links[p_node_id].parameter_name = p_parameter_name;
353}
354
355void VisualShaderGraphPlugin::update_theme() {
356 vector_expanded_color[0] = editor->get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)); // red
357 vector_expanded_color[1] = editor->get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)); // green
358 vector_expanded_color[2] = editor->get_theme_color(SNAME("axis_z_color"), EditorStringName(Editor)); // blue
359 vector_expanded_color[3] = editor->get_theme_color(SNAME("axis_w_color"), EditorStringName(Editor)); // alpha
360}
361
362bool VisualShaderGraphPlugin::is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const {
363 bool result = false;
364
365 Ref<VisualShaderNodeParameter> parameter_node = Object::cast_to<VisualShaderNodeParameter>(visual_shader->get_node_unchecked(p_type, p_node).ptr());
366 if (parameter_node.is_valid()) {
367 if (parameter_node->get_qualifier() == VisualShaderNodeParameter::QUAL_INSTANCE) {
368 return true;
369 }
370 }
371
372 const LocalVector<int> &prev_connected_nodes = visual_shader->get_prev_connected_nodes(p_type, p_node);
373
374 for (const int &E : prev_connected_nodes) {
375 result = is_node_has_parameter_instances_relatively(p_type, E);
376 if (result) {
377 break;
378 }
379 }
380
381 return result;
382}
383
384void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool p_just_update) {
385 if (!visual_shader.is_valid() || p_type != visual_shader->get_shader_type()) {
386 return;
387 }
388 GraphEdit *graph = editor->graph;
389 if (!graph) {
390 return;
391 }
392 VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();
393 if (!graph_plugin) {
394 return;
395 }
396 Shader::Mode mode = visual_shader->get_mode();
397
398 Control *offset;
399
400 static const Color type_color[] = {
401 Color(0.38, 0.85, 0.96), // scalar (float)
402 Color(0.49, 0.78, 0.94), // scalar (int)
403 Color(0.20, 0.88, 0.67), // scalar (uint)
404 Color(0.74, 0.57, 0.95), // vector2
405 Color(0.84, 0.49, 0.93), // vector3
406 Color(1.0, 0.125, 0.95), // vector4
407 Color(0.55, 0.65, 0.94), // boolean
408 Color(0.96, 0.66, 0.43), // transform
409 Color(1.0, 1.0, 0.0), // sampler
410 };
411
412 static const String vector_expanded_name[4] = {
413 "red",
414 "green",
415 "blue",
416 "alpha"
417 };
418
419 // Visual shader specific theme for MSDF font.
420 Ref<Theme> vstheme;
421 vstheme.instantiate();
422 Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", EditorStringName(EditorFonts));
423 Ref<Font> label_bold_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_bold_msdf", EditorStringName(EditorFonts));
424 vstheme->set_font("font", "Label", label_font);
425 vstheme->set_font("font", "GraphNodeTitleLabel", label_bold_font);
426 vstheme->set_font("font", "LineEdit", label_font);
427 vstheme->set_font("font", "Button", label_font);
428
429 Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);
430
431 Ref<VisualShaderNodeResizableBase> resizable_node = vsnode;
432 bool is_resizable = resizable_node.is_valid();
433 Size2 size = Size2(0, 0);
434
435 Ref<VisualShaderNodeGroupBase> group_node = vsnode;
436 bool is_group = group_node.is_valid();
437
438 Ref<VisualShaderNodeComment> comment_node = vsnode;
439 bool is_comment = comment_node.is_valid();
440
441 Ref<VisualShaderNodeExpression> expression_node = group_node;
442 bool is_expression = expression_node.is_valid();
443 String expression = "";
444
445 Ref<VisualShaderNodeCustom> custom_node = vsnode;
446 if (custom_node.is_valid()) {
447 custom_node->_set_initialized(true);
448 }
449
450 GraphNode *node = memnew(GraphNode);
451 node->set_title(vsnode->get_caption());
452
453 // All nodes are closable except the output node.
454 if (p_id >= 2) {
455 vsnode->set_closable(true);
456 node->connect("close_request", callable_mp(editor, &VisualShaderEditor::_close_node_request).bind(p_type, p_id), CONNECT_DEFERRED);
457 }
458 graph->add_child(node);
459 node->set_theme(vstheme);
460
461 if (p_just_update) {
462 Link &link = links[p_id];
463
464 link.graph_element = node;
465 link.preview_box = nullptr;
466 link.preview_pos = -1;
467 link.output_ports.clear();
468 link.input_ports.clear();
469 } else {
470 register_link(p_type, p_id, vsnode.ptr(), node);
471 }
472
473 if (is_resizable) {
474 size = resizable_node->get_size();
475
476 node->set_resizable(true);
477 node->connect("resize_request", callable_mp(editor, &VisualShaderEditor::_node_resized).bind((int)p_type, p_id));
478 }
479 if (is_expression) {
480 expression = expression_node->get_expression();
481 }
482
483 if (is_comment) {
484 node->set_visible(false);
485 }
486
487 node->set_position_offset(visual_shader->get_node_position(p_type, p_id));
488
489 node->set_name(itos(p_id));
490
491 node->connect("dragged", callable_mp(editor, &VisualShaderEditor::_node_dragged).bind(p_id));
492
493 Control *custom_editor = nullptr;
494 int port_offset = 1;
495
496 if (is_resizable) {
497 editor->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size);
498 }
499
500 Control *content_offset = memnew(Control);
501 content_offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
502 node->add_child(content_offset);
503
504 if (is_group) {
505 port_offset += 1;
506 }
507
508 Ref<VisualShaderNodeParticleEmit> emit = vsnode;
509 if (emit.is_valid()) {
510 node->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
511 }
512
513 Ref<VisualShaderNodeParameterRef> parameter_ref = vsnode;
514 if (parameter_ref.is_valid()) {
515 parameter_ref->set_shader_rid(visual_shader->get_rid());
516 parameter_ref->update_parameter_type();
517 }
518
519 Ref<VisualShaderNodeParameter> parameter = vsnode;
520 HBoxContainer *hb = nullptr;
521
522 if (parameter.is_valid()) {
523 LineEdit *parameter_name = memnew(LineEdit);
524 register_parameter_name(p_id, parameter_name);
525 parameter_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
526 parameter_name->set_text(parameter->get_parameter_name());
527 parameter_name->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_changed).bind(p_id));
528 parameter_name->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_parameter_line_edit_focus_out).bind(parameter_name, p_id));
529
530 if (vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
531 hb = memnew(HBoxContainer);
532 hb->add_child(parameter_name);
533 node->add_child(hb);
534 } else {
535 node->add_child(parameter_name);
536 }
537 port_offset++;
538 }
539
540 for (int i = 0; i < editor->plugins.size(); i++) {
541 vsnode->set_meta("id", p_id);
542 vsnode->set_meta("shader_type", (int)p_type);
543 custom_editor = editor->plugins.write[i]->create_editor(visual_shader, vsnode);
544 vsnode->remove_meta("id");
545 vsnode->remove_meta("shader_type");
546 if (custom_editor) {
547 if (vsnode->is_show_prop_names()) {
548 custom_editor->call_deferred(SNAME("_show_prop_names"), true);
549 }
550 break;
551 }
552 }
553
554 Ref<VisualShaderNodeCurveTexture> curve = vsnode;
555 Ref<VisualShaderNodeCurveXYZTexture> curve_xyz = vsnode;
556
557 bool is_curve = curve.is_valid() || curve_xyz.is_valid();
558 if (is_curve) {
559 hb = memnew(HBoxContainer);
560 node->add_child(hb);
561 }
562
563 if (curve.is_valid()) {
564 custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
565
566 if (curve->get_texture().is_valid()) {
567 curve->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve).bind(p_id));
568 }
569
570 CurveEditor *curve_editor = memnew(CurveEditor);
571 node->add_child(curve_editor);
572 register_curve_editor(p_id, 0, curve_editor);
573 curve_editor->set_custom_minimum_size(Size2(300, 0));
574 curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
575 if (curve->get_texture().is_valid()) {
576 curve_editor->set_curve(curve->get_texture()->get_curve());
577 }
578 }
579
580 if (curve_xyz.is_valid()) {
581 custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
582
583 if (curve_xyz->get_texture().is_valid()) {
584 curve_xyz->get_texture()->connect_changed(callable_mp(graph_plugin, &VisualShaderGraphPlugin::update_curve_xyz).bind(p_id));
585 }
586
587 CurveEditor *curve_editor_x = memnew(CurveEditor);
588 node->add_child(curve_editor_x);
589 register_curve_editor(p_id, 0, curve_editor_x);
590 curve_editor_x->set_custom_minimum_size(Size2(300, 0));
591 curve_editor_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
592 if (curve_xyz->get_texture().is_valid()) {
593 curve_editor_x->set_curve(curve_xyz->get_texture()->get_curve_x());
594 }
595
596 CurveEditor *curve_editor_y = memnew(CurveEditor);
597 node->add_child(curve_editor_y);
598 register_curve_editor(p_id, 1, curve_editor_y);
599 curve_editor_y->set_custom_minimum_size(Size2(300, 0));
600 curve_editor_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
601 if (curve_xyz->get_texture().is_valid()) {
602 curve_editor_y->set_curve(curve_xyz->get_texture()->get_curve_y());
603 }
604
605 CurveEditor *curve_editor_z = memnew(CurveEditor);
606 node->add_child(curve_editor_z);
607 register_curve_editor(p_id, 2, curve_editor_z);
608 curve_editor_z->set_custom_minimum_size(Size2(300, 0));
609 curve_editor_z->set_h_size_flags(Control::SIZE_EXPAND_FILL);
610 if (curve_xyz->get_texture().is_valid()) {
611 curve_editor_z->set_curve(curve_xyz->get_texture()->get_curve_z());
612 }
613 }
614
615 if (custom_editor) {
616 if (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) == ""))) {
617 // Will be embedded in first port.
618 } else {
619 port_offset++;
620 node->add_child(custom_editor);
621 custom_editor = nullptr;
622 }
623 }
624
625 if (is_group) {
626 if (group_node->is_editable()) {
627 HBoxContainer *hb2 = memnew(HBoxContainer);
628
629 String input_port_name = "input" + itos(group_node->get_free_input_port_id());
630 String output_port_name = "output" + itos(group_node->get_free_output_port_id());
631
632 for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) {
633 if (i < vsnode->get_input_port_count()) {
634 if (input_port_name == vsnode->get_input_port_name(i)) {
635 input_port_name = "_" + input_port_name;
636 }
637 }
638 if (i < vsnode->get_output_port_count()) {
639 if (output_port_name == vsnode->get_output_port_name(i)) {
640 output_port_name = "_" + output_port_name;
641 }
642 }
643 }
644
645 Button *add_input_btn = memnew(Button);
646 add_input_btn->set_text(TTR("Add Input"));
647 add_input_btn->connect("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);
648 hb2->add_child(add_input_btn);
649
650 hb2->add_spacer();
651
652 Button *add_output_btn = memnew(Button);
653 add_output_btn->set_text(TTR("Add Output"));
654 add_output_btn->connect("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);
655 hb2->add_child(add_output_btn);
656
657 node->add_child(hb2);
658 }
659 }
660
661 int output_port_count = 0;
662 for (int i = 0; i < vsnode->get_output_port_count(); i++) {
663 if (vsnode->_is_output_port_expanded(i)) {
664 switch (vsnode->get_output_port_type(i)) {
665 case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
666 output_port_count += 2;
667 } break;
668 case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
669 output_port_count += 3;
670 } break;
671 case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
672 output_port_count += 4;
673 } break;
674 default:
675 break;
676 }
677 }
678 output_port_count++;
679 }
680 int max_ports = MAX(vsnode->get_input_port_count(), output_port_count);
681 VisualShaderNode::PortType expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
682 int expanded_port_counter = 0;
683
684 for (int i = 0, j = 0; i < max_ports; i++, j++) {
685 switch (expanded_type) {
686 case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
687 if (expanded_port_counter >= 2) {
688 expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
689 expanded_port_counter = 0;
690 i -= 2;
691 }
692 } break;
693 case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
694 if (expanded_port_counter >= 3) {
695 expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
696 expanded_port_counter = 0;
697 i -= 3;
698 }
699 } break;
700 case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
701 if (expanded_port_counter >= 4) {
702 expanded_type = VisualShaderNode::PORT_TYPE_SCALAR;
703 expanded_port_counter = 0;
704 i -= 4;
705 }
706 } break;
707 default:
708 break;
709 }
710
711 if (vsnode->is_port_separator(i)) {
712 node->add_child(memnew(HSeparator));
713 port_offset++;
714 }
715
716 bool valid_left = j < vsnode->get_input_port_count();
717 VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR;
718 bool port_left_used = false;
719 String name_left;
720 if (valid_left) {
721 name_left = vsnode->get_input_port_name(i);
722 port_left = vsnode->get_input_port_type(i);
723 for (const VisualShader::Connection &E : connections) {
724 if (E.to_node == p_id && E.to_port == j) {
725 port_left_used = true;
726 break;
727 }
728 }
729 }
730
731 bool valid_right = true;
732 VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR;
733 String name_right;
734
735 if (expanded_type == VisualShaderNode::PORT_TYPE_SCALAR) {
736 valid_right = i < vsnode->get_output_port_count();
737 if (valid_right) {
738 name_right = vsnode->get_output_port_name(i);
739 port_right = vsnode->get_output_port_type(i);
740 }
741 } else {
742 name_right = vector_expanded_name[expanded_port_counter++];
743 }
744
745 bool is_first_hbox = false;
746 if (i == 0 && hb != nullptr) {
747 is_first_hbox = true;
748 } else {
749 hb = memnew(HBoxContainer);
750 }
751 hb->add_theme_constant_override("separation", 7 * EDSCALE);
752
753 Variant default_value;
754
755 if (valid_left && !port_left_used) {
756 default_value = vsnode->get_input_port_default_value(i);
757 }
758
759 Button *button = memnew(Button);
760 hb->add_child(button);
761 register_default_input_button(p_id, i, button);
762 button->connect("pressed", callable_mp(editor, &VisualShaderEditor::_edit_port_default_input).bind(button, p_id, i));
763 if (default_value.get_type() != Variant::NIL) { // only a label
764 set_input_port_default_value(p_type, p_id, i, default_value);
765 } else {
766 button->hide();
767 }
768
769 if (i == 0 && custom_editor) {
770 hb->add_child(custom_editor);
771 custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
772 } else {
773 if (valid_left) {
774 if (is_group) {
775 OptionButton *type_box = memnew(OptionButton);
776 hb->add_child(type_box);
777 type_box->add_item(TTR("Float"));
778 type_box->add_item(TTR("Int"));
779 type_box->add_item(TTR("UInt"));
780 type_box->add_item(TTR("Vector2"));
781 type_box->add_item(TTR("Vector3"));
782 type_box->add_item(TTR("Vector4"));
783 type_box->add_item(TTR("Boolean"));
784 type_box->add_item(TTR("Transform"));
785 type_box->add_item(TTR("Sampler"));
786 type_box->select(group_node->get_input_port_type(i));
787 type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
788 type_box->connect("item_selected", callable_mp(editor, &VisualShaderEditor::_change_input_port_type).bind(p_id, i), CONNECT_DEFERRED);
789
790 LineEdit *name_box = memnew(LineEdit);
791 hb->add_child(name_box);
792 name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));
793 name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
794 name_box->set_text(name_left);
795 name_box->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_change_input_port_name).bind(name_box, p_id, i), CONNECT_DEFERRED);
796 name_box->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, i, false), CONNECT_DEFERRED);
797
798 Button *remove_btn = memnew(Button);
799 remove_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
800 remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
801 remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, i), CONNECT_DEFERRED);
802 hb->add_child(remove_btn);
803 } else {
804 Label *label = memnew(Label);
805 label->set_text(name_left);
806 label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact
807 hb->add_child(label);
808
809 if (vsnode->is_input_port_default(i, mode) && !port_left_used) {
810 Label *hint_label = memnew(Label);
811 hint_label->set_text(TTR("[default]"));
812 hint_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit")));
813 hint_label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor")));
814 hb->add_child(hint_label);
815 }
816 }
817 }
818
819 if (!is_group && !is_first_hbox) {
820 hb->add_spacer();
821 }
822
823 if (valid_right) {
824 if (is_group) {
825 Button *remove_btn = memnew(Button);
826 remove_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
827 remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
828 remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED);
829 hb->add_child(remove_btn);
830
831 LineEdit *name_box = memnew(LineEdit);
832 hb->add_child(name_box);
833 name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0));
834 name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
835 name_box->set_text(name_right);
836 name_box->connect("text_submitted", callable_mp(editor, &VisualShaderEditor::_change_output_port_name).bind(name_box, p_id, i), CONNECT_DEFERRED);
837 name_box->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, i, true), CONNECT_DEFERRED);
838
839 OptionButton *type_box = memnew(OptionButton);
840 hb->add_child(type_box);
841 type_box->add_item(TTR("Float"));
842 type_box->add_item(TTR("Int"));
843 type_box->add_item(TTR("UInt"));
844 type_box->add_item(TTR("Vector2"));
845 type_box->add_item(TTR("Vector3"));
846 type_box->add_item(TTR("Vector4"));
847 type_box->add_item(TTR("Boolean"));
848 type_box->add_item(TTR("Transform"));
849 type_box->select(group_node->get_output_port_type(i));
850 type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
851 type_box->connect("item_selected", callable_mp(editor, &VisualShaderEditor::_change_output_port_type).bind(p_id, i), CONNECT_DEFERRED);
852 } else {
853 Label *label = memnew(Label);
854 label->set_text(name_right);
855 label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact
856 hb->add_child(label);
857 }
858 }
859 }
860
861 if (valid_right) {
862 if (vsnode->is_output_port_expandable(i)) {
863 TextureButton *expand = memnew(TextureButton);
864 expand->set_toggle_mode(true);
865 expand->set_texture_normal(editor->get_editor_theme_icon(SNAME("GuiTreeArrowDown")));
866 expand->set_texture_pressed(editor->get_editor_theme_icon(SNAME("GuiTreeArrowRight")));
867 expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
868 expand->set_pressed(vsnode->_is_output_port_expanded(i));
869 expand->connect("pressed", callable_mp(editor, &VisualShaderEditor::_expand_output_port).bind(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED);
870 hb->add_child(expand);
871 }
872 if (vsnode->has_output_port_preview(i) && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) {
873 TextureButton *preview = memnew(TextureButton);
874 preview->set_toggle_mode(true);
875 preview->set_texture_normal(editor->get_editor_theme_icon(SNAME("GuiVisibilityHidden")));
876 preview->set_texture_pressed(editor->get_editor_theme_icon(SNAME("GuiVisibilityVisible")));
877 preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
878
879 register_output_port(p_id, j, preview);
880
881 preview->connect("pressed", callable_mp(editor, &VisualShaderEditor::_preview_select_port).bind(p_id, j), CONNECT_DEFERRED);
882 hb->add_child(preview);
883 }
884 }
885
886 if (is_group) {
887 offset = memnew(Control);
888 offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
889 node->add_child(offset);
890 port_offset++;
891 }
892
893 if (!is_first_hbox) {
894 node->add_child(hb);
895 }
896
897 if (expanded_type != VisualShaderNode::PORT_TYPE_SCALAR) {
898 continue;
899 }
900
901 int idx = 1;
902 if (!is_first_hbox) {
903 idx = i + port_offset;
904 }
905 if (!is_comment) {
906 GraphNode *graph_node = Object::cast_to<GraphNode>(node);
907
908 graph_node->set_slot(idx, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]);
909
910 if (vsnode->_is_output_port_expanded(i)) {
911 switch (vsnode->get_output_port_type(i)) {
912 case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
913 port_offset++;
914 valid_left = (i + 1) < vsnode->get_input_port_count();
915 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
916 if (valid_left) {
917 port_left = vsnode->get_input_port_type(i + 1);
918 }
919 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
920 port_offset++;
921
922 valid_left = (i + 2) < vsnode->get_input_port_count();
923 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
924 if (valid_left) {
925 port_left = vsnode->get_input_port_type(i + 2);
926 }
927 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
928
929 expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_2D;
930 } break;
931 case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
932 port_offset++;
933 valid_left = (i + 1) < vsnode->get_input_port_count();
934 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
935 if (valid_left) {
936 port_left = vsnode->get_input_port_type(i + 1);
937 }
938 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
939 port_offset++;
940
941 valid_left = (i + 2) < vsnode->get_input_port_count();
942 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
943 if (valid_left) {
944 port_left = vsnode->get_input_port_type(i + 2);
945 }
946 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
947 port_offset++;
948
949 valid_left = (i + 3) < vsnode->get_input_port_count();
950 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
951 if (valid_left) {
952 port_left = vsnode->get_input_port_type(i + 3);
953 }
954 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);
955
956 expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_3D;
957 } break;
958 case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
959 port_offset++;
960 valid_left = (i + 1) < vsnode->get_input_port_count();
961 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
962 if (valid_left) {
963 port_left = vsnode->get_input_port_type(i + 1);
964 }
965 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]);
966 port_offset++;
967
968 valid_left = (i + 2) < vsnode->get_input_port_count();
969 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
970 if (valid_left) {
971 port_left = vsnode->get_input_port_type(i + 2);
972 }
973 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]);
974 port_offset++;
975
976 valid_left = (i + 3) < vsnode->get_input_port_count();
977 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
978 if (valid_left) {
979 port_left = vsnode->get_input_port_type(i + 3);
980 }
981 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]);
982 port_offset++;
983
984 valid_left = (i + 4) < vsnode->get_input_port_count();
985 port_left = VisualShaderNode::PORT_TYPE_SCALAR;
986 if (valid_left) {
987 port_left = vsnode->get_input_port_type(i + 4);
988 }
989 graph_node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[3]);
990
991 expanded_type = VisualShaderNode::PORT_TYPE_VECTOR_4D;
992 } break;
993 default:
994 break;
995 }
996 }
997 }
998 }
999
1000 bool has_relative_parameter_instances = false;
1001 if (vsnode->get_output_port_for_preview() >= 0) {
1002 has_relative_parameter_instances = is_node_has_parameter_instances_relatively(p_type, p_id);
1003 show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview(), !has_relative_parameter_instances);
1004 } else {
1005 offset = memnew(Control);
1006 offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
1007 node->add_child(offset);
1008 }
1009
1010 String error = vsnode->get_warning(mode, p_type);
1011 if (has_relative_parameter_instances) {
1012 error += "\n" + TTR("The 2D preview cannot correctly show the result retrieved from instance parameter.");
1013 }
1014 if (!error.is_empty()) {
1015 Label *error_label = memnew(Label);
1016 error_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
1017 error_label->set_text(error);
1018 error_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
1019 node->add_child(error_label);
1020 }
1021
1022 if (is_expression) {
1023 CodeEdit *expression_box = memnew(CodeEdit);
1024 Ref<CodeHighlighter> expression_syntax_highlighter;
1025 expression_syntax_highlighter.instantiate();
1026 expression_node->set_ctrl_pressed(expression_box, 0);
1027 node->add_child(expression_box);
1028 register_expression_edit(p_id, expression_box);
1029
1030 Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color");
1031 Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");
1032 Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
1033 Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
1034 Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
1035 Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");
1036 Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");
1037 Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");
1038 Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
1039
1040 expression_box->set_syntax_highlighter(expression_syntax_highlighter);
1041 expression_box->add_theme_color_override("background_color", background_color);
1042
1043 for (const String &E : editor->keyword_list) {
1044 if (ShaderLanguage::is_control_flow_keyword(E)) {
1045 expression_syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);
1046 } else {
1047 expression_syntax_highlighter->add_keyword_color(E, keyword_color);
1048 }
1049 }
1050
1051 expression_box->add_theme_font_override("font", editor->get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)));
1052 expression_box->add_theme_font_size_override("font_size", editor->get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts)));
1053 expression_box->add_theme_color_override("font_color", text_color);
1054 expression_syntax_highlighter->set_number_color(number_color);
1055 expression_syntax_highlighter->set_symbol_color(symbol_color);
1056 expression_syntax_highlighter->set_function_color(function_color);
1057 expression_syntax_highlighter->set_member_variable_color(members_color);
1058 expression_syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
1059 expression_syntax_highlighter->add_color_region("//", "", comment_color, true);
1060
1061 expression_box->clear_comment_delimiters();
1062 expression_box->add_comment_delimiter("/*", "*/", false);
1063 expression_box->add_comment_delimiter("//", "", true);
1064
1065 if (!expression_box->has_auto_brace_completion_open_key("/*")) {
1066 expression_box->add_auto_brace_completion_pair("/*", "*/");
1067 }
1068
1069 expression_box->set_text(expression);
1070 expression_box->set_context_menu_enabled(false);
1071 expression_box->set_draw_line_numbers(true);
1072
1073 expression_box->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_expression_focus_out).bind(expression_box, p_id));
1074 }
1075}
1076
1077void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id, bool p_just_update) {
1078 if (visual_shader->get_shader_type() == p_type && links.has(p_id)) {
1079 Node *graph_edit_node = links[p_id].graph_element->get_parent();
1080 graph_edit_node->remove_child(links[p_id].graph_element);
1081 memdelete(links[p_id].graph_element);
1082 if (!p_just_update) {
1083 links.erase(p_id);
1084 }
1085 }
1086}
1087
1088void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
1089 GraphEdit *graph = editor->graph;
1090 if (!graph) {
1091 return;
1092 }
1093
1094 if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) {
1095 graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
1096
1097 connections.push_back({ p_from_node, p_from_port, p_to_node, p_to_port });
1098 if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr) {
1099 links[p_to_node].input_ports[p_to_port].default_input_button->hide();
1100 }
1101 }
1102}
1103
1104void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
1105 GraphEdit *graph = editor->graph;
1106 if (!graph) {
1107 return;
1108 }
1109
1110 if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) {
1111 graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
1112
1113 for (const List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {
1114 if (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) {
1115 connections.erase(E);
1116 break;
1117 }
1118 }
1119 if (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) {
1120 links[p_to_node].input_ports[p_to_port].default_input_button->show();
1121 set_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));
1122 }
1123 }
1124}
1125
1126VisualShaderGraphPlugin::~VisualShaderGraphPlugin() {
1127}
1128
1129/////////////////
1130
1131void VisualShaderEditedProperty::_bind_methods() {
1132 ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualShaderEditedProperty::set_edited_property);
1133 ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualShaderEditedProperty::get_edited_property);
1134
1135 ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property");
1136}
1137
1138void VisualShaderEditedProperty::set_edited_property(Variant p_variant) {
1139 edited_property = p_variant;
1140}
1141
1142Variant VisualShaderEditedProperty::get_edited_property() const {
1143 return edited_property;
1144}
1145
1146/////////////////
1147
1148Vector2 VisualShaderEditor::selection_center;
1149List<VisualShaderEditor::CopyItem> VisualShaderEditor::copy_items_buffer;
1150List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer;
1151
1152void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
1153 bool changed = false;
1154 if (p_visual_shader) {
1155 if (visual_shader.is_null()) {
1156 changed = true;
1157 } else {
1158 if (visual_shader.ptr() != p_visual_shader) {
1159 changed = true;
1160 }
1161 }
1162 visual_shader = Ref<VisualShader>(p_visual_shader);
1163 graph_plugin->register_shader(visual_shader.ptr());
1164
1165 visual_shader->connect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));
1166 visual_shader->set_graph_offset(graph->get_scroll_offset() / EDSCALE);
1167 _set_mode(visual_shader->get_mode());
1168
1169 _update_nodes();
1170 } else {
1171 if (visual_shader.is_valid()) {
1172 visual_shader->disconnect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));
1173 }
1174 visual_shader.unref();
1175 }
1176
1177 if (visual_shader.is_null()) {
1178 hide();
1179 } else {
1180 if (changed) { // to avoid tree collapse
1181 _update_varying_tree();
1182 _update_options_menu();
1183 _update_preview();
1184 _update_graph();
1185 }
1186 }
1187}
1188
1189void VisualShaderEditor::add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {
1190 if (plugins.has(p_plugin)) {
1191 return;
1192 }
1193 plugins.push_back(p_plugin);
1194}
1195
1196void VisualShaderEditor::remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) {
1197 plugins.erase(p_plugin);
1198}
1199
1200void VisualShaderEditor::clear_custom_types() {
1201 for (int i = 0; i < add_options.size(); i++) {
1202 if (add_options[i].is_custom) {
1203 add_options.remove_at(i);
1204 i--;
1205 }
1206 }
1207}
1208
1209void 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) {
1210 ERR_FAIL_COND(!p_name.is_valid_identifier());
1211 ERR_FAIL_COND(p_type.is_empty() && !p_script.is_valid());
1212
1213 for (int i = 0; i < add_options.size(); i++) {
1214 const AddOption &op = add_options[i];
1215
1216 if (op.is_custom) {
1217 if (!p_type.is_empty()) {
1218 if (op.type == p_type) {
1219 return;
1220 }
1221 } else if (op.script == p_script) {
1222 return;
1223 }
1224 }
1225 }
1226
1227 AddOption ao;
1228 ao.name = p_name;
1229 ao.type = p_type;
1230 ao.script = p_script;
1231 ao.return_type = p_return_icon_type;
1232 ao.description = p_description;
1233 ao.category = p_category;
1234 ao.highend = p_highend;
1235 ao.is_custom = true;
1236 ao.is_native = !p_type.is_empty();
1237
1238 bool begin = false;
1239 String root = p_category.split("/")[0];
1240
1241 for (int i = 0; i < add_options.size(); i++) {
1242 if (add_options[i].is_custom) {
1243 if (add_options[i].category == root) {
1244 if (!begin) {
1245 begin = true;
1246 }
1247 } else {
1248 if (begin) {
1249 add_options.insert(i, ao);
1250 return;
1251 }
1252 }
1253 }
1254 }
1255 add_options.push_back(ao);
1256}
1257
1258Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) {
1259 Dictionary dict;
1260 dict["script"] = p_custom_node->get_script();
1261 dict["name"] = p_custom_node->_get_name();
1262 dict["description"] = p_custom_node->_get_description();
1263 dict["return_icon_type"] = p_custom_node->_get_return_icon_type();
1264 dict["highend"] = p_custom_node->_is_highend();
1265
1266 String category = p_custom_node->_get_category();
1267 category = category.rstrip("/");
1268 category = category.lstrip("/");
1269 category = "Addons/" + category;
1270 if (p_custom_node->has_method("_get_subcategory")) {
1271 String subcategory = (String)p_custom_node->call("_get_subcategory");
1272 if (!subcategory.is_empty()) {
1273 category += "/" + subcategory;
1274 }
1275 }
1276 dict["category"] = category;
1277
1278 return dict;
1279}
1280
1281void VisualShaderEditor::_get_current_mode_limits(int &r_begin_type, int &r_end_type) const {
1282 switch (visual_shader->get_mode()) {
1283 case Shader::MODE_CANVAS_ITEM:
1284 case Shader::MODE_SPATIAL: {
1285 r_begin_type = 0;
1286 r_end_type = 3;
1287 } break;
1288 case Shader::MODE_PARTICLES: {
1289 r_begin_type = 3;
1290 r_end_type = 5 + r_begin_type;
1291 } break;
1292 case Shader::MODE_SKY: {
1293 r_begin_type = 8;
1294 r_end_type = 1 + r_begin_type;
1295 } break;
1296 case Shader::MODE_FOG: {
1297 r_begin_type = 9;
1298 r_end_type = 1 + r_begin_type;
1299 } break;
1300 default: {
1301 } break;
1302 }
1303}
1304
1305void VisualShaderEditor::_script_created(const Ref<Script> &p_script) {
1306 if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {
1307 return;
1308 }
1309 Ref<VisualShaderNodeCustom> ref;
1310 ref.instantiate();
1311 ref->set_script(p_script);
1312
1313 Dictionary dict = get_custom_node_data(ref);
1314 add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
1315
1316 _update_options_menu();
1317}
1318
1319void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) {
1320 if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {
1321 return;
1322 }
1323
1324 Ref<VisualShaderNodeCustom> ref;
1325 ref.instantiate();
1326 ref->set_script(p_script);
1327 if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
1328 for (int i = 0; i < add_options.size(); i++) {
1329 if (add_options[i].is_custom && add_options[i].script == p_script) {
1330 add_options.remove_at(i);
1331 _update_options_menu();
1332 // TODO: Make indication for the existed custom nodes with that script on graph to be disabled.
1333 break;
1334 }
1335 }
1336 return;
1337 }
1338 Dictionary dict = get_custom_node_data(ref);
1339
1340 bool found_type = false;
1341 bool need_rebuild = false;
1342
1343 for (int i = custom_node_option_idx; i < add_options.size(); i++) {
1344 if (add_options[i].script == p_script) {
1345 found_type = true;
1346
1347 add_options.write[i].name = dict["name"];
1348 add_options.write[i].return_type = dict["return_icon_type"];
1349 add_options.write[i].description = dict["description"];
1350 add_options.write[i].category = dict["category"];
1351 add_options.write[i].highend = dict["highend"];
1352
1353 int begin_type = 0;
1354 int end_type = 0;
1355 _get_current_mode_limits(begin_type, end_type);
1356
1357 for (int t = begin_type; t < end_type; t++) {
1358 VisualShader::Type type = (VisualShader::Type)t;
1359 Vector<int> nodes = visual_shader->get_node_list(type);
1360
1361 List<VisualShader::Connection> node_connections;
1362 visual_shader->get_node_connections(type, &node_connections);
1363
1364 List<VisualShader::Connection> custom_node_input_connections;
1365 List<VisualShader::Connection> custom_node_output_connections;
1366
1367 for (const VisualShader::Connection &E : node_connections) {
1368 int from = E.from_node;
1369 int from_port = E.from_port;
1370 int to = E.to_node;
1371 int to_port = E.to_port;
1372
1373 if (graph_plugin->get_node_script(from) == p_script) {
1374 custom_node_output_connections.push_back({ from, from_port, to, to_port });
1375 } else if (graph_plugin->get_node_script(to) == p_script) {
1376 custom_node_input_connections.push_back({ from, from_port, to, to_port });
1377 }
1378 }
1379
1380 for (int node_id : nodes) {
1381 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
1382 if (vsnode.is_null()) {
1383 continue;
1384 }
1385 Ref<VisualShaderNodeCustom> custom_node = vsnode;
1386 if (custom_node.is_null() || custom_node->get_script() != p_script) {
1387 continue;
1388 }
1389 need_rebuild = true;
1390
1391 // Removes invalid connections.
1392 {
1393 int prev_input_port_count = custom_node->get_input_port_count();
1394 int prev_output_port_count = custom_node->get_output_port_count();
1395
1396 custom_node->update_ports();
1397
1398 int input_port_count = custom_node->get_input_port_count();
1399 int output_port_count = custom_node->get_output_port_count();
1400
1401 if (output_port_count != prev_output_port_count) {
1402 for (const VisualShader::Connection &E : custom_node_output_connections) {
1403 int from = E.from_node;
1404 int from_idx = E.from_port;
1405 int to = E.to_node;
1406 int to_idx = E.to_port;
1407
1408 if (from_idx >= output_port_count) {
1409 visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);
1410 graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);
1411 }
1412 }
1413 }
1414 if (input_port_count != prev_input_port_count) {
1415 for (const VisualShader::Connection &E : custom_node_input_connections) {
1416 int from = E.from_node;
1417 int from_idx = E.from_port;
1418 int to = E.to_node;
1419 int to_idx = E.to_port;
1420
1421 if (to_idx >= input_port_count) {
1422 visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx);
1423 graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx);
1424 }
1425 }
1426 }
1427 }
1428
1429 graph_plugin->update_node(type, node_id);
1430 }
1431 }
1432 break;
1433 }
1434 }
1435
1436 if (!found_type) {
1437 add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
1438 }
1439
1440 // To prevent updating options multiple times when multiple scripts are saved.
1441 if (!_block_update_options_menu) {
1442 _block_update_options_menu = true;
1443
1444 call_deferred(SNAME("_update_options_menu_deferred"));
1445 }
1446
1447 // To prevent rebuilding the shader multiple times when multiple scripts are saved.
1448 if (need_rebuild && !_block_rebuild_shader) {
1449 _block_rebuild_shader = true;
1450
1451 call_deferred(SNAME("_rebuild_shader_deferred"));
1452 }
1453}
1454
1455void VisualShaderEditor::_resource_saved(const Ref<Resource> &p_resource) {
1456 _update_custom_script(Ref<Script>(p_resource.ptr()));
1457}
1458
1459void VisualShaderEditor::_resources_removed() {
1460 bool has_any_instance = false;
1461
1462 for (const Ref<Script> &scr : custom_scripts_to_delete) {
1463 for (int i = custom_node_option_idx; i < add_options.size(); i++) {
1464 if (add_options[i].script == scr) {
1465 add_options.remove_at(i);
1466
1467 // Removes all node instances using that script from the graph.
1468 {
1469 int begin_type = 0;
1470 int end_type = 0;
1471 _get_current_mode_limits(begin_type, end_type);
1472
1473 for (int t = begin_type; t < end_type; t++) {
1474 VisualShader::Type type = (VisualShader::Type)t;
1475
1476 List<VisualShader::Connection> node_connections;
1477 visual_shader->get_node_connections(type, &node_connections);
1478
1479 for (const VisualShader::Connection &E : node_connections) {
1480 int from = E.from_node;
1481 int from_port = E.from_port;
1482 int to = E.to_node;
1483 int to_port = E.to_port;
1484
1485 if (graph_plugin->get_node_script(from) == scr || graph_plugin->get_node_script(to) == scr) {
1486 visual_shader->disconnect_nodes(type, from, from_port, to, to_port);
1487 graph_plugin->disconnect_nodes(type, from, from_port, to, to_port);
1488 }
1489 }
1490
1491 Vector<int> nodes = visual_shader->get_node_list(type);
1492 for (int node_id : nodes) {
1493 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
1494 if (vsnode.is_null()) {
1495 continue;
1496 }
1497 Ref<VisualShaderNodeCustom> custom_node = vsnode;
1498 if (custom_node.is_null() || custom_node->get_script() != scr) {
1499 continue;
1500 }
1501 visual_shader->remove_node(type, node_id);
1502 graph_plugin->remove_node(type, node_id, false);
1503
1504 has_any_instance = true;
1505 }
1506 }
1507 }
1508
1509 break;
1510 }
1511 }
1512 }
1513 if (has_any_instance) {
1514 EditorUndoRedoManager::get_singleton()->clear_history(); // Need to clear undo history, otherwise it may lead to hard-detected errors and crashes (since the script was removed).
1515 ResourceSaver::save(visual_shader, visual_shader->get_path());
1516 }
1517 _update_options_menu();
1518
1519 custom_scripts_to_delete.clear();
1520 pending_custom_scripts_to_delete = false;
1521}
1522
1523void VisualShaderEditor::_resource_removed(const Ref<Resource> &p_resource) {
1524 Ref<Script> scr = Ref<Script>(p_resource.ptr());
1525 if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") {
1526 return;
1527 }
1528
1529 custom_scripts_to_delete.push_back(scr);
1530
1531 if (!pending_custom_scripts_to_delete) {
1532 pending_custom_scripts_to_delete = true;
1533
1534 call_deferred("_resources_removed");
1535 }
1536}
1537
1538void VisualShaderEditor::_update_options_menu_deferred() {
1539 _update_options_menu();
1540
1541 _block_update_options_menu = false;
1542}
1543
1544void VisualShaderEditor::_rebuild_shader_deferred() {
1545 if (visual_shader.is_valid()) {
1546 visual_shader->rebuild();
1547 }
1548
1549 _block_rebuild_shader = false;
1550}
1551
1552bool VisualShaderEditor::_is_available(int p_mode) {
1553 int current_mode = edit_type->get_selected();
1554
1555 if (p_mode != -1) {
1556 switch (current_mode) {
1557 case 0: // Vertex / Emit
1558 current_mode = 1;
1559 break;
1560 case 1: // Fragment / Process
1561 current_mode = 2;
1562 break;
1563 case 2: // Light / Collide
1564 current_mode = 4;
1565 break;
1566 default:
1567 break;
1568 }
1569 }
1570
1571 return (p_mode == -1 || (p_mode & current_mode) != 0);
1572}
1573
1574void VisualShaderEditor::_update_nodes() {
1575 clear_custom_types();
1576 Dictionary added;
1577
1578 // Add GDScript classes.
1579 {
1580 List<StringName> class_list;
1581 ScriptServer::get_global_class_list(&class_list);
1582
1583 for (int i = 0; i < class_list.size(); i++) {
1584 if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") {
1585 String script_path = ScriptServer::get_global_class_path(class_list[i]);
1586 Ref<Resource> res = ResourceLoader::load(script_path);
1587 ERR_CONTINUE(res.is_null());
1588 ERR_CONTINUE(!res->is_class("Script"));
1589 Ref<Script> scr = Ref<Script>(res);
1590
1591 Ref<VisualShaderNodeCustom> ref;
1592 ref.instantiate();
1593 ref->set_script(scr);
1594 if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
1595 continue;
1596 }
1597 Dictionary dict = get_custom_node_data(ref);
1598 dict["type"] = String();
1599
1600 String key;
1601 key = String(dict["category"]) + "/" + String(dict["name"]);
1602
1603 added[key] = dict;
1604 }
1605 }
1606 }
1607
1608 // Add GDExtension classes.
1609 {
1610 List<StringName> class_list;
1611 ClassDB::get_class_list(&class_list);
1612
1613 for (int i = 0; i < class_list.size(); i++) {
1614 if (ClassDB::get_parent_class(class_list[i]) == "VisualShaderNodeCustom") {
1615 Object *instance = ClassDB::instantiate(class_list[i]);
1616 Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance);
1617 ERR_CONTINUE(ref.is_null());
1618 if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
1619 continue;
1620 }
1621 Dictionary dict = get_custom_node_data(ref);
1622 dict["type"] = class_list[i];
1623 dict["script"] = Ref<Script>();
1624
1625 String key;
1626 key = String(dict["category"]) + "/" + String(dict["name"]);
1627
1628 added[key] = dict;
1629 }
1630 }
1631 }
1632
1633 // Disables not-supported copied items.
1634 {
1635 for (CopyItem &item : copy_items_buffer) {
1636 Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(item.node.ptr());
1637
1638 if (custom.is_valid()) {
1639 if (!custom->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
1640 item.disabled = true;
1641 } else {
1642 item.disabled = false;
1643 }
1644 } else {
1645 for (int i = 0; i < add_options.size(); i++) {
1646 if (add_options[i].type == item.node->get_class_name()) {
1647 if ((add_options[i].func != visual_shader->get_mode() && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {
1648 item.disabled = true;
1649 } else {
1650 item.disabled = false;
1651 }
1652 break;
1653 }
1654 }
1655 }
1656 }
1657 }
1658
1659 Array keys = added.keys();
1660 keys.sort();
1661
1662 for (int i = 0; i < keys.size(); i++) {
1663 const Variant &key = keys.get(i);
1664
1665 const Dictionary &value = (Dictionary)added[key];
1666
1667 add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);
1668 }
1669
1670 _update_options_menu();
1671}
1672
1673String VisualShaderEditor::_get_description(int p_idx) {
1674 return add_options[p_idx].description;
1675}
1676
1677void VisualShaderEditor::_update_options_menu() {
1678 node_desc->set_text("");
1679 members_dialog->get_ok_button()->set_disabled(true);
1680
1681 members->clear();
1682 TreeItem *root = members->create_item();
1683
1684 String filter = node_filter->get_text().strip_edges();
1685 bool use_filter = !filter.is_empty();
1686
1687 bool is_first_item = true;
1688
1689 Color unsupported_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
1690 Color supported_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
1691
1692 static bool low_driver = GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility";
1693
1694 HashMap<String, TreeItem *> folders;
1695
1696 int current_func = -1;
1697
1698 if (!visual_shader.is_null()) {
1699 current_func = visual_shader->get_mode();
1700 }
1701
1702 Vector<AddOption> custom_options;
1703 Vector<AddOption> embedded_options;
1704
1705 static Vector<String> type_filter_exceptions;
1706 if (type_filter_exceptions.is_empty()) {
1707 type_filter_exceptions.append("VisualShaderNodeExpression");
1708 }
1709
1710 for (int i = 0; i < add_options.size(); i++) {
1711 if (!use_filter || add_options[i].name.findn(filter) != -1) {
1712 // port type filtering
1713 if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX || members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
1714 Ref<VisualShaderNode> vsn;
1715 int check_result = 0;
1716
1717 if (!add_options[i].is_custom) {
1718 vsn = Ref<VisualShaderNode>(Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[i].type)));
1719 if (!vsn.is_valid()) {
1720 continue;
1721 }
1722
1723 if (type_filter_exceptions.has(add_options[i].type)) {
1724 check_result = 1;
1725 }
1726
1727 Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(vsn.ptr());
1728 if (input.is_valid()) {
1729 input->set_shader_mode(visual_shader->get_mode());
1730 input->set_shader_type(visual_shader->get_shader_type());
1731 if (!add_options[i].ops.is_empty() && add_options[i].ops[0].get_type() == Variant::STRING) {
1732 input->set_input_name((String)add_options[i].ops[0]);
1733 }
1734 }
1735
1736 Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(vsn.ptr());
1737 if (expression.is_valid()) {
1738 if (members_input_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
1739 check_result = -1; // expressions creates a port with required type automatically (except for sampler output)
1740 }
1741 }
1742
1743 Ref<VisualShaderNodeParameterRef> parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn.ptr());
1744 if (parameter_ref.is_valid()) {
1745 check_result = -1;
1746
1747 if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
1748 for (int j = 0; j < parameter_ref->get_parameters_count(); j++) {
1749 if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(j), members_input_port_type)) {
1750 check_result = 1;
1751 break;
1752 }
1753 }
1754 }
1755 }
1756 } else {
1757 check_result = 1;
1758 }
1759
1760 if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX) {
1761 if (check_result == 0) {
1762 for (int j = 0; j < vsn->get_input_port_count(); j++) {
1763 if (visual_shader->is_port_types_compatible(vsn->get_input_port_type(j), members_output_port_type)) {
1764 check_result = 1;
1765 break;
1766 }
1767 }
1768 }
1769
1770 if (check_result != 1) {
1771 continue;
1772 }
1773 }
1774 if (members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
1775 if (check_result == 0) {
1776 for (int j = 0; j < vsn->get_output_port_count(); j++) {
1777 if (visual_shader->is_port_types_compatible(vsn->get_output_port_type(j), members_input_port_type)) {
1778 check_result = 1;
1779 break;
1780 }
1781 }
1782 }
1783
1784 if (check_result != 1) {
1785 continue;
1786 }
1787 }
1788 }
1789 if ((add_options[i].func != current_func && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {
1790 continue;
1791 }
1792 const_cast<AddOption &>(add_options[i]).temp_idx = i; // save valid id
1793 if (add_options[i].is_custom) {
1794 custom_options.push_back(add_options[i]);
1795 } else {
1796 embedded_options.push_back(add_options[i]);
1797 }
1798 }
1799 }
1800 Vector<AddOption> options;
1801 SortArray<AddOption, _OptionComparator> sorter;
1802 sorter.sort(custom_options.ptrw(), custom_options.size());
1803
1804 options.append_array(custom_options);
1805 options.append_array(embedded_options);
1806
1807 for (int i = 0; i < options.size(); i++) {
1808 String path = options[i].category;
1809 Vector<String> subfolders = path.split("/");
1810 TreeItem *category = nullptr;
1811
1812 if (!folders.has(path)) {
1813 category = root;
1814 String path_temp = "";
1815 for (int j = 0; j < subfolders.size(); j++) {
1816 path_temp += subfolders[j];
1817 if (!folders.has(path_temp)) {
1818 category = members->create_item(category);
1819 category->set_selectable(0, false);
1820 category->set_collapsed(!use_filter);
1821 category->set_text(0, subfolders[j]);
1822 folders.insert(path_temp, category);
1823 } else {
1824 category = folders[path_temp];
1825 }
1826 }
1827 } else {
1828 category = folders[path];
1829 }
1830
1831 TreeItem *item = members->create_item(category);
1832 if (options[i].highend && low_driver) {
1833 item->set_custom_color(0, unsupported_color);
1834 } else if (options[i].highend) {
1835 item->set_custom_color(0, supported_color);
1836 }
1837 item->set_text(0, options[i].name);
1838 if (is_first_item && use_filter) {
1839 item->select(0);
1840 node_desc->set_text(options[i].description);
1841 is_first_item = false;
1842 }
1843 switch (options[i].return_type) {
1844 case VisualShaderNode::PORT_TYPE_SCALAR:
1845 item->set_icon(0, get_editor_theme_icon(SNAME("float")));
1846 break;
1847 case VisualShaderNode::PORT_TYPE_SCALAR_INT:
1848 item->set_icon(0, get_editor_theme_icon(SNAME("int")));
1849 break;
1850 case VisualShaderNode::PORT_TYPE_SCALAR_UINT:
1851 item->set_icon(0, get_editor_theme_icon(SNAME("uint")));
1852 break;
1853 case VisualShaderNode::PORT_TYPE_VECTOR_2D:
1854 item->set_icon(0, get_editor_theme_icon(SNAME("Vector2")));
1855 break;
1856 case VisualShaderNode::PORT_TYPE_VECTOR_3D:
1857 item->set_icon(0, get_editor_theme_icon(SNAME("Vector3")));
1858 break;
1859 case VisualShaderNode::PORT_TYPE_VECTOR_4D:
1860 item->set_icon(0, get_editor_theme_icon(SNAME("Vector4")));
1861 break;
1862 case VisualShaderNode::PORT_TYPE_BOOLEAN:
1863 item->set_icon(0, get_editor_theme_icon(SNAME("bool")));
1864 break;
1865 case VisualShaderNode::PORT_TYPE_TRANSFORM:
1866 item->set_icon(0, get_editor_theme_icon(SNAME("Transform3D")));
1867 break;
1868 case VisualShaderNode::PORT_TYPE_SAMPLER:
1869 item->set_icon(0, get_editor_theme_icon(SNAME("ImageTexture")));
1870 break;
1871 default:
1872 break;
1873 }
1874 item->set_meta("id", options[i].temp_idx);
1875 }
1876}
1877
1878void VisualShaderEditor::_set_mode(int p_which) {
1879 if (p_which == VisualShader::MODE_SKY) {
1880 edit_type_standard->set_visible(false);
1881 edit_type_particles->set_visible(false);
1882 edit_type_sky->set_visible(true);
1883 edit_type_fog->set_visible(false);
1884 edit_type = edit_type_sky;
1885 custom_mode_box->set_visible(false);
1886 varying_button->hide();
1887 mode = MODE_FLAGS_SKY;
1888 } else if (p_which == VisualShader::MODE_FOG) {
1889 edit_type_standard->set_visible(false);
1890 edit_type_particles->set_visible(false);
1891 edit_type_sky->set_visible(false);
1892 edit_type_fog->set_visible(true);
1893 edit_type = edit_type_fog;
1894 custom_mode_box->set_visible(false);
1895 varying_button->hide();
1896 mode = MODE_FLAGS_FOG;
1897 } else if (p_which == VisualShader::MODE_PARTICLES) {
1898 edit_type_standard->set_visible(false);
1899 edit_type_particles->set_visible(true);
1900 edit_type_sky->set_visible(false);
1901 edit_type_fog->set_visible(false);
1902 edit_type = edit_type_particles;
1903 if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {
1904 custom_mode_box->set_visible(false);
1905 } else {
1906 custom_mode_box->set_visible(true);
1907 }
1908 varying_button->hide();
1909 mode = MODE_FLAGS_PARTICLES;
1910 } else {
1911 edit_type_particles->set_visible(false);
1912 edit_type_standard->set_visible(true);
1913 edit_type_sky->set_visible(false);
1914 edit_type_fog->set_visible(false);
1915 edit_type = edit_type_standard;
1916 custom_mode_box->set_visible(false);
1917 varying_button->show();
1918 mode = MODE_FLAGS_SPATIAL_CANVASITEM;
1919 }
1920 visual_shader->set_shader_type(get_current_shader_type());
1921}
1922
1923Size2 VisualShaderEditor::get_minimum_size() const {
1924 return Size2(10, 200);
1925}
1926
1927void VisualShaderEditor::_draw_color_over_button(Object *p_obj, Color p_color) {
1928 Button *button = Object::cast_to<Button>(p_obj);
1929 if (!button) {
1930 return;
1931 }
1932
1933 Ref<StyleBox> normal = get_theme_stylebox(SNAME("normal"), SNAME("Button"));
1934 button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);
1935}
1936
1937void VisualShaderEditor::_update_parameters(bool p_update_refs) {
1938 VisualShaderNodeParameterRef::clear_parameters(visual_shader->get_rid());
1939
1940 for (int t = 0; t < VisualShader::TYPE_MAX; t++) {
1941 Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t);
1942 for (int i = 0; i < tnodes.size(); i++) {
1943 Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]);
1944 Ref<VisualShaderNodeParameter> parameter = vsnode;
1945
1946 if (parameter.is_valid()) {
1947 Ref<VisualShaderNodeFloatParameter> float_parameter = vsnode;
1948 Ref<VisualShaderNodeIntParameter> int_parameter = vsnode;
1949 Ref<VisualShaderNodeUIntParameter> uint_parameter = vsnode;
1950 Ref<VisualShaderNodeVec2Parameter> vec2_parameter = vsnode;
1951 Ref<VisualShaderNodeVec3Parameter> vec3_parameter = vsnode;
1952 Ref<VisualShaderNodeVec4Parameter> vec4_parameter = vsnode;
1953 Ref<VisualShaderNodeColorParameter> color_parameter = vsnode;
1954 Ref<VisualShaderNodeBooleanParameter> boolean_parameter = vsnode;
1955 Ref<VisualShaderNodeTransformParameter> transform_parameter = vsnode;
1956
1957 VisualShaderNodeParameterRef::ParameterType parameter_type;
1958 if (float_parameter.is_valid()) {
1959 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_FLOAT;
1960 } else if (int_parameter.is_valid()) {
1961 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_INT;
1962 } else if (uint_parameter.is_valid()) {
1963 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_UINT;
1964 } else if (boolean_parameter.is_valid()) {
1965 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_BOOLEAN;
1966 } else if (vec2_parameter.is_valid()) {
1967 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR2;
1968 } else if (vec3_parameter.is_valid()) {
1969 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR3;
1970 } else if (vec4_parameter.is_valid()) {
1971 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_VECTOR4;
1972 } else if (transform_parameter.is_valid()) {
1973 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_TRANSFORM;
1974 } else if (color_parameter.is_valid()) {
1975 parameter_type = VisualShaderNodeParameterRef::PARAMETER_TYPE_COLOR;
1976 } else {
1977 parameter_type = VisualShaderNodeParameterRef::UNIFORM_TYPE_SAMPLER;
1978 }
1979 VisualShaderNodeParameterRef::add_parameter(visual_shader->get_rid(), parameter->get_parameter_name(), parameter_type);
1980 }
1981 }
1982 }
1983 if (p_update_refs) {
1984 graph_plugin->update_parameter_refs();
1985 }
1986}
1987
1988void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) {
1989 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
1990 for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
1991 VisualShader::Type type = VisualShader::Type(i);
1992
1993 Vector<int> nodes = visual_shader->get_node_list(type);
1994 for (int j = 0; j < nodes.size(); j++) {
1995 if (j > 0) {
1996 Ref<VisualShaderNodeParameterRef> ref = visual_shader->get_node(type, nodes[j]);
1997 if (ref.is_valid()) {
1998 if (p_deleted_names.has(ref->get_parameter_name())) {
1999 undo_redo->add_do_method(ref.ptr(), "set_parameter_name", "[None]");
2000 undo_redo->add_undo_method(ref.ptr(), "set_parameter_name", ref->get_parameter_name());
2001 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
2002 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
2003 }
2004 }
2005 }
2006 }
2007 }
2008}
2009
2010void VisualShaderEditor::_update_graph() {
2011 if (updating) {
2012 return;
2013 }
2014
2015 if (visual_shader.is_null()) {
2016 return;
2017 }
2018
2019 graph->set_scroll_offset(visual_shader->get_graph_offset() * EDSCALE);
2020
2021 VisualShader::Type type = get_current_shader_type();
2022
2023 graph->clear_connections();
2024 // Remove all nodes.
2025 for (int i = 0; i < graph->get_child_count(); i++) {
2026 if (Object::cast_to<GraphElement>(graph->get_child(i))) {
2027 Node *node = graph->get_child(i);
2028 graph->remove_child(node);
2029 memdelete(node);
2030 i--;
2031 }
2032 }
2033
2034 List<VisualShader::Connection> node_connections;
2035 visual_shader->get_node_connections(type, &node_connections);
2036 graph_plugin->set_connections(node_connections);
2037
2038 Vector<int> nodes = visual_shader->get_node_list(type);
2039
2040 _update_parameters(false);
2041 _update_varyings();
2042
2043 graph_plugin->clear_links();
2044 graph_plugin->update_theme();
2045
2046 for (int n_i = 0; n_i < nodes.size(); n_i++) {
2047 graph_plugin->add_node(type, nodes[n_i], false);
2048 }
2049
2050 for (const VisualShader::Connection &E : node_connections) {
2051 int from = E.from_node;
2052 int from_idx = E.from_port;
2053 int to = E.to_node;
2054 int to_idx = E.to_port;
2055
2056 graph->connect_node(itos(from), from_idx, itos(to), to_idx);
2057 }
2058
2059 float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
2060 graph->set_minimap_opacity(graph_minimap_opacity);
2061 float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
2062 graph->set_connection_lines_curvature(graph_lines_curvature);
2063}
2064
2065VisualShader::Type VisualShaderEditor::get_current_shader_type() const {
2066 VisualShader::Type type;
2067 if (mode & MODE_FLAGS_PARTICLES) {
2068 type = VisualShader::Type(edit_type->get_selected() + 3 + (custom_mode_enabled ? 3 : 0));
2069 } else if (mode & MODE_FLAGS_SKY) {
2070 type = VisualShader::Type(edit_type->get_selected() + 8);
2071 } else if (mode & MODE_FLAGS_FOG) {
2072 type = VisualShader::Type(edit_type->get_selected() + 9);
2073 } else {
2074 type = VisualShader::Type(edit_type->get_selected());
2075 }
2076 return type;
2077}
2078
2079void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) {
2080 VisualShader::Type type = get_current_shader_type();
2081 Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);
2082 if (node.is_null()) {
2083 return;
2084 }
2085
2086 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2087 undo_redo->create_action(TTR("Add Input Port"));
2088 undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name);
2089 undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port);
2090 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
2091 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
2092 undo_redo->commit_action();
2093}
2094
2095void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_type, const String &p_name) {
2096 VisualShader::Type type = get_current_shader_type();
2097 Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
2098 if (node.is_null()) {
2099 return;
2100 }
2101
2102 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2103 undo_redo->create_action(TTR("Add Output Port"));
2104 undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name);
2105 undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port);
2106 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
2107 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
2108 undo_redo->commit_action();
2109}
2110
2111void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_port) {
2112 VisualShader::Type type = get_current_shader_type();
2113 Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
2114 if (node.is_null()) {
2115 return;
2116 }
2117
2118 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2119 undo_redo->create_action(TTR("Change Input Port Type"));
2120 undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type);
2121 undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port));
2122 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
2123 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
2124 undo_redo->commit_action();
2125}
2126
2127void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_port) {
2128 VisualShader::Type type = get_current_shader_type();
2129 Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
2130 if (node.is_null()) {
2131 return;
2132 }
2133
2134 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2135 undo_redo->create_action(TTR("Change Output Port Type"));
2136 undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type);
2137 undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port));
2138 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
2139 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
2140 undo_redo->commit_action();
2141}
2142
2143void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p_line_edit, int p_node_id, int p_port_id) {
2144 VisualShader::Type type = get_current_shader_type();
2145
2146 Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);
2147 ERR_FAIL_COND(!node.is_valid());
2148
2149 String prev_name = node->get_input_port_name(p_port_id);
2150 if (prev_name == p_text) {
2151 return;
2152 }
2153
2154 LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);
2155 ERR_FAIL_NULL(line_edit);
2156
2157 String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, false);
2158 if (validated_name.is_empty() || prev_name == validated_name) {
2159 line_edit->set_text(node->get_input_port_name(p_port_id));
2160 return;
2161 }
2162
2163 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2164 undo_redo->create_action(TTR("Change Input Port Name"));
2165 undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, validated_name);
2166 undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id));
2167 undo_redo->commit_action();
2168}
2169
2170void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *p_line_edit, int p_node_id, int p_port_id) {
2171 VisualShader::Type type = get_current_shader_type();
2172
2173 Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);
2174 ERR_FAIL_COND(!node.is_valid());
2175
2176 String prev_name = node->get_output_port_name(p_port_id);
2177 if (prev_name == p_text) {
2178 return;
2179 }
2180
2181 LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);
2182 ERR_FAIL_NULL(line_edit);
2183
2184 String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, true);
2185 if (validated_name.is_empty() || prev_name == validated_name) {
2186 line_edit->set_text(node->get_output_port_name(p_port_id));
2187 return;
2188 }
2189
2190 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2191 undo_redo->create_action(TTR("Change Output Port Name"));
2192 undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, validated_name);
2193 undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, prev_name);
2194 undo_redo->commit_action();
2195}
2196
2197void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expand) {
2198 VisualShader::Type type = get_current_shader_type();
2199
2200 Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);
2201 ERR_FAIL_COND(!node.is_valid());
2202
2203 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2204 if (p_expand) {
2205 undo_redo->create_action(TTR("Expand Output Port"));
2206 } else {
2207 undo_redo->create_action(TTR("Shrink Output Port"));
2208 }
2209
2210 undo_redo->add_do_method(node.ptr(), "_set_output_port_expanded", p_port, p_expand);
2211 undo_redo->add_undo_method(node.ptr(), "_set_output_port_expanded", p_port, !p_expand);
2212
2213 int type_size = 0;
2214 switch (node->get_output_port_type(p_port)) {
2215 case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
2216 type_size = 2;
2217 } break;
2218 case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
2219 type_size = 3;
2220 } break;
2221 case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
2222 type_size = 4;
2223 } break;
2224 default:
2225 break;
2226 }
2227
2228 List<VisualShader::Connection> conns;
2229 visual_shader->get_node_connections(type, &conns);
2230
2231 for (const VisualShader::Connection &E : conns) {
2232 int cn_from_node = E.from_node;
2233 int cn_from_port = E.from_port;
2234 int cn_to_node = E.to_node;
2235 int cn_to_port = E.to_port;
2236
2237 if (cn_from_node == p_node) {
2238 if (p_expand) {
2239 if (cn_from_port > p_port) { // reconnect ports after expanded ports
2240 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2241 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2242
2243 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2244 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2245
2246 undo_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);
2247 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);
2248
2249 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);
2250 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);
2251 }
2252 } else {
2253 if (cn_from_port > p_port + type_size) { // reconnect ports after expanded ports
2254 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2255 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2256
2257 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2258 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2259
2260 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
2261 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
2262
2263 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
2264 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
2265 } else if (cn_from_port > p_port) { // disconnect component ports
2266 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2267 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2268
2269 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2270 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2271 }
2272 }
2273 }
2274 }
2275
2276 int preview_port = node->get_output_port_for_preview();
2277 if (p_expand) {
2278 if (preview_port > p_port) {
2279 undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port + type_size);
2280 undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);
2281 }
2282 } else {
2283 if (preview_port > p_port + type_size) {
2284 undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - type_size);
2285 undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);
2286 }
2287 }
2288
2289 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
2290 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
2291 undo_redo->commit_action();
2292}
2293
2294void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {
2295 VisualShader::Type type = get_current_shader_type();
2296 Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
2297 if (node.is_null()) {
2298 return;
2299 }
2300
2301 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2302 undo_redo->create_action(TTR("Remove Input Port"));
2303
2304 List<VisualShader::Connection> conns;
2305 visual_shader->get_node_connections(type, &conns);
2306 for (const VisualShader::Connection &E : conns) {
2307 int cn_from_node = E.from_node;
2308 int cn_from_port = E.from_port;
2309 int cn_to_node = E.to_node;
2310 int cn_to_port = E.to_port;
2311
2312 if (cn_to_node == p_node) {
2313 if (cn_to_port == p_port) {
2314 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2315 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2316
2317 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2318 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2319 } else if (cn_to_port > p_port) {
2320 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2321 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2322
2323 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2324 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2325
2326 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
2327 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
2328
2329 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
2330 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
2331 }
2332 }
2333 }
2334
2335 undo_redo->add_do_method(node.ptr(), "remove_input_port", p_port);
2336 undo_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));
2337
2338 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
2339 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
2340
2341 undo_redo->commit_action();
2342}
2343
2344void VisualShaderEditor::_remove_output_port(int p_node, int p_port) {
2345 VisualShader::Type type = get_current_shader_type();
2346 Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
2347 if (node.is_null()) {
2348 return;
2349 }
2350
2351 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2352 undo_redo->create_action(TTR("Remove Output Port"));
2353
2354 List<VisualShader::Connection> conns;
2355 visual_shader->get_node_connections(type, &conns);
2356 for (const VisualShader::Connection &E : conns) {
2357 int cn_from_node = E.from_node;
2358 int cn_from_port = E.from_port;
2359 int cn_to_node = E.to_node;
2360 int cn_to_port = E.to_port;
2361
2362 if (cn_from_node == p_node) {
2363 if (cn_from_port == p_port) {
2364 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2365 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2366
2367 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2368 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2369 } else if (cn_from_port > p_port) {
2370 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2371 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2372
2373 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2374 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
2375
2376 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
2377 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
2378
2379 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
2380 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
2381 }
2382 }
2383 }
2384
2385 int preview_port = node->get_output_port_for_preview();
2386 if (preview_port != -1) {
2387 if (preview_port == p_port) {
2388 undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", -1);
2389 undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);
2390 } else if (preview_port > p_port) {
2391 undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - 1);
2392 undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port);
2393 }
2394 }
2395
2396 undo_redo->add_do_method(node.ptr(), "remove_output_port", p_port);
2397 undo_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));
2398
2399 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node);
2400 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node);
2401
2402 undo_redo->commit_action();
2403}
2404
2405void VisualShaderEditor::_expression_focus_out(Object *p_code_edit, int p_node) {
2406 VisualShader::Type type = get_current_shader_type();
2407 Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);
2408 if (node.is_null()) {
2409 return;
2410 }
2411
2412 CodeEdit *expression_box = Object::cast_to<CodeEdit>(p_code_edit);
2413
2414 if (node->get_expression() == expression_box->get_text()) {
2415 return;
2416 }
2417
2418 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2419 undo_redo->create_action(TTR("Set VisualShader Expression"));
2420 undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text());
2421 undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression());
2422 undo_redo->add_do_method(graph_plugin.ptr(), "set_expression", type, p_node, expression_box->get_text());
2423 undo_redo->add_undo_method(graph_plugin.ptr(), "set_expression", type, p_node, node->get_expression());
2424 undo_redo->commit_action();
2425}
2426
2427void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) {
2428 VisualShader::Type type = VisualShader::Type(p_type);
2429 Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(type, p_node);
2430 if (node.is_null()) {
2431 return;
2432 }
2433
2434 Size2 size = p_size;
2435 if (!node->is_allow_v_resize()) {
2436 size.y = 0;
2437 }
2438
2439 node->set_size(size);
2440
2441 if (get_current_shader_type() == type) {
2442 Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
2443 Control *text_box = nullptr;
2444 if (!expression_node.is_null()) {
2445 text_box = expression_node->is_ctrl_pressed(0);
2446 if (text_box) {
2447 text_box->set_custom_minimum_size(Size2(0, 0));
2448 }
2449 }
2450
2451 GraphElement *graph_element = nullptr;
2452 Node *node2 = graph->get_node(itos(p_node));
2453 graph_element = Object::cast_to<GraphElement>(node2);
2454 if (!graph_element) {
2455 return;
2456 }
2457
2458 graph_element->set_custom_minimum_size(size);
2459 graph_element->reset_size();
2460
2461 if (!expression_node.is_null() && text_box) {
2462 Size2 box_size = size;
2463 if (box_size.x < 150 * EDSCALE || box_size.y < 0) {
2464 box_size.x = graph_element->get_size().x;
2465 }
2466 box_size.x -= text_box->get_offset(SIDE_LEFT);
2467 box_size.x -= 28 * EDSCALE;
2468 box_size.y -= text_box->get_offset(SIDE_TOP);
2469 box_size.y -= 28 * EDSCALE;
2470 text_box->set_custom_minimum_size(box_size);
2471 text_box->reset_size();
2472 }
2473 }
2474}
2475
2476void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, int p_node) {
2477 Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(VisualShader::Type(p_type), p_node);
2478 if (node.is_null()) {
2479 return;
2480 }
2481
2482 Vector2 new_size = p_new_size;
2483 if (graph->is_snapping_enabled() ^ Input::get_singleton()->is_key_pressed(Key::CTRL)) {
2484 new_size = new_size.snapped(Vector2(graph->get_snapping_distance(), graph->get_snapping_distance()));
2485 }
2486
2487 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2488 undo_redo->create_action(TTR("Resize VisualShader Node"), UndoRedo::MERGE_ENDS);
2489 undo_redo->add_do_method(this, "_set_node_size", p_type, p_node, new_size);
2490 undo_redo->add_undo_method(this, "_set_node_size", p_type, p_node, node->get_size());
2491 undo_redo->commit_action();
2492}
2493
2494void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {
2495 VisualShader::Type type = get_current_shader_type();
2496 Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);
2497 if (node.is_null()) {
2498 return;
2499 }
2500 int prev_port = node->get_output_port_for_preview();
2501 if (node->get_output_port_for_preview() == p_port) {
2502 p_port = -1; //toggle it
2503 }
2504 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2505 undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview"));
2506 undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port);
2507 undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port);
2508 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, p_node);
2509 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, p_node);
2510 undo_redo->commit_action();
2511}
2512
2513void VisualShaderEditor::_comment_title_popup_show(const Point2 &p_position, int p_node_id) {
2514 VisualShader::Type type = get_current_shader_type();
2515 Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, p_node_id);
2516 if (node.is_null()) {
2517 return;
2518 }
2519 comment_title_change_edit->set_text(node->get_title());
2520 comment_title_change_popup->set_meta("id", p_node_id);
2521 comment_title_change_popup->popup();
2522 comment_title_change_popup->set_position(p_position);
2523}
2524
2525void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) {
2526 comment_title_change_edit->reset_size();
2527 comment_title_change_popup->reset_size();
2528}
2529
2530void VisualShaderEditor::_comment_title_text_submitted(const String &p_new_text) {
2531 comment_title_change_popup->hide();
2532}
2533
2534void VisualShaderEditor::_comment_title_popup_focus_out() {
2535 comment_title_change_popup->hide();
2536}
2537
2538void VisualShaderEditor::_comment_title_popup_hide() {
2539 ERR_FAIL_COND(!comment_title_change_popup->has_meta("id"));
2540 int node_id = (int)comment_title_change_popup->get_meta("id");
2541
2542 VisualShader::Type type = get_current_shader_type();
2543 Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, node_id);
2544
2545 ERR_FAIL_COND(node.is_null());
2546
2547 if (node->get_title() == comment_title_change_edit->get_text()) {
2548 return; // nothing changed - ignored
2549 }
2550 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2551 undo_redo->create_action(TTR("Set Comment Title"));
2552 undo_redo->add_do_method(node.ptr(), "set_title", comment_title_change_edit->get_text());
2553 undo_redo->add_undo_method(node.ptr(), "set_title", node->get_title());
2554 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
2555 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
2556 undo_redo->commit_action();
2557}
2558
2559void VisualShaderEditor::_comment_desc_popup_show(const Point2 &p_position, int p_node_id) {
2560 VisualShader::Type type = get_current_shader_type();
2561 Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, p_node_id);
2562 if (node.is_null()) {
2563 return;
2564 }
2565 comment_desc_change_edit->set_text(node->get_description());
2566 comment_desc_change_popup->set_meta("id", p_node_id);
2567 comment_desc_change_popup->reset_size();
2568 comment_desc_change_popup->popup();
2569 comment_desc_change_popup->set_position(p_position);
2570}
2571
2572void VisualShaderEditor::_comment_desc_text_changed() {
2573 comment_desc_change_edit->reset_size();
2574 comment_desc_change_popup->reset_size();
2575}
2576
2577void VisualShaderEditor::_comment_desc_confirm() {
2578 comment_desc_change_popup->hide();
2579}
2580
2581void VisualShaderEditor::_comment_desc_popup_hide() {
2582 ERR_FAIL_COND(!comment_desc_change_popup->has_meta("id"));
2583 int node_id = (int)comment_desc_change_popup->get_meta("id");
2584
2585 VisualShader::Type type = get_current_shader_type();
2586 Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, node_id);
2587
2588 ERR_FAIL_COND(node.is_null());
2589
2590 if (node->get_description() == comment_desc_change_edit->get_text()) {
2591 return; // nothing changed - ignored
2592 }
2593 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2594 undo_redo->create_action(TTR("Set Comment Description"));
2595 undo_redo->add_do_method(node.ptr(), "set_description", comment_desc_change_edit->get_text());
2596 undo_redo->add_undo_method(node.ptr(), "set_description", node->get_title());
2597 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
2598 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
2599 undo_redo->commit_action();
2600}
2601
2602void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int p_node_id) {
2603 VisualShader::Type type = get_current_shader_type();
2604
2605 Ref<VisualShaderNodeParameter> node = visual_shader->get_node(type, p_node_id);
2606 ERR_FAIL_COND(!node.is_valid());
2607
2608 String validated_name = visual_shader->validate_parameter_name(p_text, node);
2609
2610 if (validated_name == node->get_parameter_name()) {
2611 return;
2612 }
2613
2614 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2615 undo_redo->create_action(TTR("Set Parameter Name"));
2616 undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);
2617 undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());
2618 undo_redo->add_do_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, validated_name);
2619 undo_redo->add_undo_method(graph_plugin.ptr(), "set_parameter_name", type, p_node_id, node->get_parameter_name());
2620 undo_redo->add_do_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
2621 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node_deferred", type, p_node_id);
2622
2623 undo_redo->add_do_method(this, "_update_parameters", true);
2624 undo_redo->add_undo_method(this, "_update_parameters", true);
2625
2626 HashSet<String> changed_names;
2627 changed_names.insert(node->get_parameter_name());
2628 _update_parameter_refs(changed_names);
2629
2630 undo_redo->commit_action();
2631}
2632
2633void VisualShaderEditor::_parameter_line_edit_focus_out(Object *line_edit, int p_node_id) {
2634 _parameter_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id);
2635}
2636
2637void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) {
2638 if (!p_output) {
2639 _change_input_port_name(Object::cast_to<LineEdit>(line_edit)->get_text(), line_edit, p_node_id, p_port_id);
2640 } else {
2641 _change_output_port_name(Object::cast_to<LineEdit>(line_edit)->get_text(), line_edit, p_node_id, p_port_id);
2642 }
2643}
2644
2645void VisualShaderEditor::_port_edited(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
2646 VisualShader::Type type = get_current_shader_type();
2647 Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node);
2648 ERR_FAIL_COND(!vsn.is_valid());
2649
2650 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
2651 undo_redo->create_action(TTR("Set Input Default Port"));
2652
2653 Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());
2654 if (custom.is_valid()) {
2655 undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, p_value);
2656 undo_redo->add_undo_method(custom.ptr(), "_set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
2657 } else {
2658 undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, p_value);
2659 undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
2660 }
2661 undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, p_value);
2662 undo_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));
2663 undo_redo->commit_action();
2664}
2665
2666void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node, int p_port) {
2667 VisualShader::Type type = get_current_shader_type();
2668 Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, p_node);
2669 Variant value = vs_node->get_input_port_default_value(p_port);
2670
2671 edited_property_holder->set_edited_property(value);
2672
2673 if (property_editor) {
2674 property_editor->disconnect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
2675 property_editor_popup->remove_child(property_editor);
2676 }
2677
2678 // TODO: Define these properties with actual PropertyInfo and feed it to the property editor widget.
2679 property_editor = EditorInspector::instantiate_property_editor(edited_property_holder.ptr(), value.get_type(), "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE);
2680 if (property_editor) {
2681 property_editor->set_object_and_property(edited_property_holder.ptr(), "edited_property");
2682 property_editor->update_property();
2683 property_editor->set_name_split_ratio(0);
2684 property_editor_popup->add_child(property_editor);
2685
2686 property_editor->connect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
2687
2688 Button *button = Object::cast_to<Button>(p_button);
2689 if (button) {
2690 property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom());
2691 }
2692 property_editor_popup->reset_size();
2693 if (button) {
2694 property_editor_popup->popup();
2695 } else {
2696 property_editor_popup->popup_centered_ratio();
2697 }
2698 }
2699
2700 editing_node = p_node;
2701 editing_port = p_port;
2702}
2703
2704void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, const Vector<Variant> &p_ops) {
2705 // INPUT
2706 {
2707 VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(p_node);
2708
2709 if (input) {
2710 ERR_FAIL_COND(p_ops[0].get_type() != Variant::STRING);
2711 input->set_input_name((String)p_ops[0]);
2712 return;
2713 }
2714 }
2715
2716 // FLOAT_CONST
2717 {
2718 VisualShaderNodeFloatConstant *float_const = Object::cast_to<VisualShaderNodeFloatConstant>(p_node);
2719
2720 if (float_const) {
2721 ERR_FAIL_COND(p_ops[0].get_type() != Variant::FLOAT);
2722 float_const->set_constant((float)p_ops[0]);
2723 return;
2724 }
2725 }
2726
2727 // FLOAT_OP
2728 {
2729 VisualShaderNodeFloatOp *floatOp = Object::cast_to<VisualShaderNodeFloatOp>(p_node);
2730
2731 if (floatOp) {
2732 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2733 floatOp->set_operator((VisualShaderNodeFloatOp::Operator)(int)p_ops[0]);
2734 return;
2735 }
2736 }
2737
2738 // FLOAT_FUNC
2739 {
2740 VisualShaderNodeFloatFunc *floatFunc = Object::cast_to<VisualShaderNodeFloatFunc>(p_node);
2741
2742 if (floatFunc) {
2743 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2744 floatFunc->set_function((VisualShaderNodeFloatFunc::Function)(int)p_ops[0]);
2745 return;
2746 }
2747 }
2748
2749 // VECTOR_OP
2750 {
2751 VisualShaderNodeVectorOp *vecOp = Object::cast_to<VisualShaderNodeVectorOp>(p_node);
2752
2753 if (vecOp) {
2754 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2755 ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);
2756 vecOp->set_operator((VisualShaderNodeVectorOp::Operator)(int)p_ops[0]);
2757 vecOp->set_op_type((VisualShaderNodeVectorOp::OpType)(int)p_ops[1]);
2758 return;
2759 }
2760 }
2761
2762 // VECTOR_FUNC
2763 {
2764 VisualShaderNodeVectorFunc *vecFunc = Object::cast_to<VisualShaderNodeVectorFunc>(p_node);
2765
2766 if (vecFunc) {
2767 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2768 ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);
2769 vecFunc->set_function((VisualShaderNodeVectorFunc::Function)(int)p_ops[0]);
2770 vecFunc->set_op_type((VisualShaderNodeVectorFunc::OpType)(int)p_ops[1]);
2771 return;
2772 }
2773 }
2774
2775 // COLOR_OP
2776 {
2777 VisualShaderNodeColorOp *colorOp = Object::cast_to<VisualShaderNodeColorOp>(p_node);
2778
2779 if (colorOp) {
2780 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2781 colorOp->set_operator((VisualShaderNodeColorOp::Operator)(int)p_ops[0]);
2782 return;
2783 }
2784 }
2785
2786 // COLOR_FUNC
2787 {
2788 VisualShaderNodeColorFunc *colorFunc = Object::cast_to<VisualShaderNodeColorFunc>(p_node);
2789
2790 if (colorFunc) {
2791 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2792 colorFunc->set_function((VisualShaderNodeColorFunc::Function)(int)p_ops[0]);
2793 return;
2794 }
2795 }
2796
2797 // INT_OP
2798 {
2799 VisualShaderNodeIntOp *intOp = Object::cast_to<VisualShaderNodeIntOp>(p_node);
2800
2801 if (intOp) {
2802 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2803 intOp->set_operator((VisualShaderNodeIntOp::Operator)(int)p_ops[0]);
2804 return;
2805 }
2806 }
2807
2808 // INT_FUNC
2809 {
2810 VisualShaderNodeIntFunc *intFunc = Object::cast_to<VisualShaderNodeIntFunc>(p_node);
2811
2812 if (intFunc) {
2813 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2814 intFunc->set_function((VisualShaderNodeIntFunc::Function)(int)p_ops[0]);
2815 return;
2816 }
2817 }
2818
2819 // UINT_OP
2820 {
2821 VisualShaderNodeUIntOp *uintOp = Object::cast_to<VisualShaderNodeUIntOp>(p_node);
2822
2823 if (uintOp) {
2824 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2825 uintOp->set_operator((VisualShaderNodeUIntOp::Operator)(int)p_ops[0]);
2826 return;
2827 }
2828 }
2829
2830 // UINT_FUNC
2831 {
2832 VisualShaderNodeUIntFunc *uintFunc = Object::cast_to<VisualShaderNodeUIntFunc>(p_node);
2833
2834 if (uintFunc) {
2835 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2836 uintFunc->set_function((VisualShaderNodeUIntFunc::Function)(int)p_ops[0]);
2837 return;
2838 }
2839 }
2840
2841 // TRANSFORM_OP
2842 {
2843 VisualShaderNodeTransformOp *matOp = Object::cast_to<VisualShaderNodeTransformOp>(p_node);
2844
2845 if (matOp) {
2846 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2847 matOp->set_operator((VisualShaderNodeTransformOp::Operator)(int)p_ops[0]);
2848 return;
2849 }
2850 }
2851
2852 // TRANSFORM_FUNC
2853 {
2854 VisualShaderNodeTransformFunc *matFunc = Object::cast_to<VisualShaderNodeTransformFunc>(p_node);
2855
2856 if (matFunc) {
2857 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2858 matFunc->set_function((VisualShaderNodeTransformFunc::Function)(int)p_ops[0]);
2859 return;
2860 }
2861 }
2862
2863 // VECTOR_COMPOSE
2864 {
2865 VisualShaderNodeVectorCompose *vecCompose = Object::cast_to<VisualShaderNodeVectorCompose>(p_node);
2866
2867 if (vecCompose) {
2868 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2869 vecCompose->set_op_type((VisualShaderNodeVectorCompose::OpType)(int)p_ops[0]);
2870 return;
2871 }
2872 }
2873
2874 // VECTOR_DECOMPOSE
2875 {
2876 VisualShaderNodeVectorDecompose *vecDecompose = Object::cast_to<VisualShaderNodeVectorDecompose>(p_node);
2877
2878 if (vecDecompose) {
2879 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2880 vecDecompose->set_op_type((VisualShaderNodeVectorDecompose::OpType)(int)p_ops[0]);
2881 return;
2882 }
2883 }
2884
2885 // UV_FUNC
2886 {
2887 VisualShaderNodeUVFunc *uvFunc = Object::cast_to<VisualShaderNodeUVFunc>(p_node);
2888
2889 if (uvFunc) {
2890 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2891 uvFunc->set_function((VisualShaderNodeUVFunc::Function)(int)p_ops[0]);
2892 return;
2893 }
2894 }
2895
2896 // IS
2897 {
2898 VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(p_node);
2899
2900 if (is) {
2901 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2902 is->set_function((VisualShaderNodeIs::Function)(int)p_ops[0]);
2903 return;
2904 }
2905 }
2906
2907 // COMPARE
2908 {
2909 VisualShaderNodeCompare *cmp = Object::cast_to<VisualShaderNodeCompare>(p_node);
2910
2911 if (cmp) {
2912 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2913 cmp->set_function((VisualShaderNodeCompare::Function)(int)p_ops[0]);
2914 return;
2915 }
2916 }
2917
2918 // DISTANCE
2919 {
2920 VisualShaderNodeVectorDistance *dist = Object::cast_to<VisualShaderNodeVectorDistance>(p_node);
2921
2922 if (dist) {
2923 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2924 dist->set_op_type((VisualShaderNodeVectorDistance::OpType)(int)p_ops[0]);
2925 return;
2926 }
2927 }
2928
2929 // DERIVATIVE
2930 {
2931 VisualShaderNodeDerivativeFunc *derFunc = Object::cast_to<VisualShaderNodeDerivativeFunc>(p_node);
2932
2933 if (derFunc) {
2934 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2935 ERR_FAIL_COND(p_ops[1].get_type() != Variant::INT);
2936 derFunc->set_function((VisualShaderNodeDerivativeFunc::Function)(int)p_ops[0]);
2937 derFunc->set_op_type((VisualShaderNodeDerivativeFunc::OpType)(int)p_ops[1]);
2938 return;
2939 }
2940 }
2941
2942 // MIX
2943 {
2944 VisualShaderNodeMix *mix = Object::cast_to<VisualShaderNodeMix>(p_node);
2945
2946 if (mix) {
2947 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2948 mix->set_op_type((VisualShaderNodeMix::OpType)(int)p_ops[0]);
2949 return;
2950 }
2951 }
2952
2953 // CLAMP
2954 {
2955 VisualShaderNodeClamp *clampFunc = Object::cast_to<VisualShaderNodeClamp>(p_node);
2956
2957 if (clampFunc) {
2958 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2959 clampFunc->set_op_type((VisualShaderNodeClamp::OpType)(int)p_ops[0]);
2960 return;
2961 }
2962 }
2963
2964 // SWITCH
2965 {
2966 VisualShaderNodeSwitch *switchFunc = Object::cast_to<VisualShaderNodeSwitch>(p_node);
2967
2968 if (switchFunc) {
2969 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2970 switchFunc->set_op_type((VisualShaderNodeSwitch::OpType)(int)p_ops[0]);
2971 return;
2972 }
2973 }
2974
2975 // FACEFORWARD
2976 {
2977 VisualShaderNodeFaceForward *faceForward = Object::cast_to<VisualShaderNodeFaceForward>(p_node);
2978 if (faceForward) {
2979 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2980 faceForward->set_op_type((VisualShaderNodeFaceForward::OpType)(int)p_ops[0]);
2981 return;
2982 }
2983 }
2984
2985 // LENGTH
2986 {
2987 VisualShaderNodeVectorLen *length = Object::cast_to<VisualShaderNodeVectorLen>(p_node);
2988 if (length) {
2989 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
2990 length->set_op_type((VisualShaderNodeVectorLen::OpType)(int)p_ops[0]);
2991 return;
2992 }
2993 }
2994
2995 // SMOOTHSTEP
2996 {
2997 VisualShaderNodeSmoothStep *smoothStepFunc = Object::cast_to<VisualShaderNodeSmoothStep>(p_node);
2998
2999 if (smoothStepFunc) {
3000 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
3001 smoothStepFunc->set_op_type((VisualShaderNodeSmoothStep::OpType)(int)p_ops[0]);
3002 return;
3003 }
3004 }
3005
3006 // STEP
3007 {
3008 VisualShaderNodeStep *stepFunc = Object::cast_to<VisualShaderNodeStep>(p_node);
3009
3010 if (stepFunc) {
3011 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
3012 stepFunc->set_op_type((VisualShaderNodeStep::OpType)(int)p_ops[0]);
3013 return;
3014 }
3015 }
3016
3017 // MULTIPLY_ADD
3018 {
3019 VisualShaderNodeMultiplyAdd *fmaFunc = Object::cast_to<VisualShaderNodeMultiplyAdd>(p_node);
3020
3021 if (fmaFunc) {
3022 ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT);
3023 fmaFunc->set_op_type((VisualShaderNodeMultiplyAdd::OpType)(int)p_ops[0]);
3024 }
3025 }
3026}
3027
3028void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, String p_resource_path, int p_node_idx) {
3029 ERR_FAIL_INDEX(p_idx, add_options.size());
3030
3031 VisualShader::Type type = get_current_shader_type();
3032
3033 Ref<VisualShaderNode> vsnode;
3034
3035 bool is_custom = add_options[p_idx].is_custom;
3036
3037 if (!is_custom && !add_options[p_idx].type.is_empty()) {
3038 VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[p_idx].type));
3039 ERR_FAIL_NULL(vsn);
3040 if (!p_ops.is_empty()) {
3041 _setup_node(vsn, p_ops);
3042 }
3043 VisualShaderNodeParameterRef *parameter_ref = Object::cast_to<VisualShaderNodeParameterRef>(vsn);
3044 if (parameter_ref && to_node != -1 && to_slot != -1) {
3045 VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);
3046 bool success = false;
3047
3048 for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
3049 if (parameter_ref->get_port_type_by_index(i) == input_port_type) {
3050 parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
3051 success = true;
3052 break;
3053 }
3054 }
3055 if (!success) {
3056 for (int i = 0; i < parameter_ref->get_parameters_count(); i++) {
3057 if (visual_shader->is_port_types_compatible(parameter_ref->get_port_type_by_index(i), input_port_type)) {
3058 parameter_ref->set_parameter_name(parameter_ref->get_parameter_name_by_index(i));
3059 break;
3060 }
3061 }
3062 }
3063 }
3064
3065 vsnode = Ref<VisualShaderNode>(vsn);
3066 } else {
3067 StringName base_type;
3068 bool is_native = add_options[p_idx].is_native;
3069
3070 if (is_native) {
3071 base_type = add_options[p_idx].type;
3072 } else {
3073 ERR_FAIL_COND(add_options[p_idx].script.is_null());
3074 base_type = add_options[p_idx].script->get_instance_base_type();
3075 }
3076 VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));
3077 ERR_FAIL_NULL(vsn);
3078 vsnode = Ref<VisualShaderNode>(vsn);
3079 if (!is_native) {
3080 vsnode->set_script(add_options[p_idx].script);
3081 }
3082 VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsn);
3083 ERR_FAIL_NULL(custom_node);
3084 custom_node->update_ports();
3085 }
3086
3087 bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr);
3088 bool is_texture3d = (Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr()) != nullptr);
3089 bool is_texture2d_array = (Object::cast_to<VisualShaderNodeTexture2DArray>(vsnode.ptr()) != nullptr);
3090 bool is_cubemap = (Object::cast_to<VisualShaderNodeCubemap>(vsnode.ptr()) != nullptr);
3091 bool is_curve = (Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr()) != nullptr);
3092 bool is_curve_xyz = (Object::cast_to<VisualShaderNodeCurveXYZTexture>(vsnode.ptr()) != nullptr);
3093 bool is_parameter = (Object::cast_to<VisualShaderNodeParameter>(vsnode.ptr()) != nullptr);
3094
3095 Point2 position = graph->get_scroll_offset();
3096
3097 if (saved_node_pos_dirty) {
3098 position += saved_node_pos;
3099 } else {
3100 position += graph->get_size() * 0.5;
3101 position /= EDSCALE;
3102 }
3103 position /= graph->get_zoom();
3104 saved_node_pos_dirty = false;
3105
3106 int id_to_use = visual_shader->get_valid_node_id(type);
3107
3108 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3109 if (p_resource_path.is_empty()) {
3110 undo_redo->create_action(TTR("Add Node to Visual Shader"));
3111 } else {
3112 id_to_use += p_node_idx;
3113 }
3114 undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, vsnode, position, id_to_use);
3115 undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_to_use);
3116 undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_to_use, false);
3117 undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_to_use, false);
3118
3119 VisualShaderNodeExpression *expr = Object::cast_to<VisualShaderNodeExpression>(vsnode.ptr());
3120 if (expr) {
3121 expr->set_size(Size2(250 * EDSCALE, 150 * EDSCALE));
3122 }
3123
3124 bool created_expression_port = false;
3125
3126 if (to_node != -1 && to_slot != -1) {
3127 VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot);
3128
3129 if (expr && expr->is_editable() && input_port_type != VisualShaderNode::PORT_TYPE_SAMPLER) {
3130 expr->add_output_port(0, input_port_type, "output0");
3131 String initial_expression_code;
3132
3133 switch (input_port_type) {
3134 case VisualShaderNode::PORT_TYPE_SCALAR:
3135 initial_expression_code = "output0 = 1.0;";
3136 break;
3137 case VisualShaderNode::PORT_TYPE_SCALAR_INT:
3138 initial_expression_code = "output0 = 1;";
3139 break;
3140 case VisualShaderNode::PORT_TYPE_SCALAR_UINT:
3141 initial_expression_code = "output0 = 1u;";
3142 break;
3143 case VisualShaderNode::PORT_TYPE_VECTOR_2D:
3144 initial_expression_code = "output0 = vec2(1.0, 1.0);";
3145 break;
3146 case VisualShaderNode::PORT_TYPE_VECTOR_3D:
3147 initial_expression_code = "output0 = vec3(1.0, 1.0, 1.0);";
3148 break;
3149 case VisualShaderNode::PORT_TYPE_VECTOR_4D:
3150 initial_expression_code = "output0 = vec4(1.0, 1.0, 1.0, 1.0);";
3151 break;
3152 case VisualShaderNode::PORT_TYPE_BOOLEAN:
3153 initial_expression_code = "output0 = true;";
3154 break;
3155 case VisualShaderNode::PORT_TYPE_TRANSFORM:
3156 initial_expression_code = "output0 = mat4(1.0);";
3157 break;
3158 default:
3159 break;
3160 }
3161
3162 expr->set_expression(initial_expression_code);
3163 expr->set_size(Size2(500 * EDSCALE, 200 * EDSCALE));
3164 created_expression_port = true;
3165 }
3166 if (vsnode->get_output_port_count() > 0 || created_expression_port) {
3167 int _from_node = id_to_use;
3168
3169 if (created_expression_port) {
3170 int _from_slot = 0;
3171 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);
3172 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);
3173 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot);
3174 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot);
3175 } else {
3176 // Need to setting up Input node properly before committing since `is_port_types_compatible` (calling below) is using `mode` and `shader_type`.
3177 VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsnode.ptr());
3178 if (input) {
3179 input->set_shader_mode(visual_shader->get_mode());
3180 input->set_shader_type(visual_shader->get_shader_type());
3181 }
3182
3183 // Attempting to connect to the first correct port.
3184 for (int i = 0; i < vsnode->get_output_port_count(); i++) {
3185 if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type)) {
3186 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);
3187 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot);
3188 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot);
3189 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot);
3190 break;
3191 }
3192 }
3193 }
3194 }
3195 } else if (from_node != -1 && from_slot != -1) {
3196 VisualShaderNode::PortType output_port_type = visual_shader->get_node(type, from_node)->get_output_port_type(from_slot);
3197
3198 if (expr && expr->is_editable()) {
3199 expr->add_input_port(0, output_port_type, "input0");
3200 created_expression_port = true;
3201 }
3202
3203 if (vsnode->get_input_port_count() > 0 || created_expression_port) {
3204 int _to_node = id_to_use;
3205
3206 if (created_expression_port) {
3207 int _to_slot = 0;
3208 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3209 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3210 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3211 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3212 } else {
3213 int _to_slot = -1;
3214
3215 // Attempting to connect to the default input port or to the first correct port (if it's not found).
3216 for (int i = 0; i < vsnode->get_input_port_count(); i++) {
3217 if (visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(i))) {
3218 if (i == vsnode->get_default_input_port(output_port_type)) {
3219 _to_slot = i;
3220 break;
3221 } else if (_to_slot == -1) {
3222 _to_slot = i;
3223 }
3224 }
3225 }
3226
3227 if (_to_slot >= 0) {
3228 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3229 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3230 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3231 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot);
3232 }
3233 }
3234
3235 if (output_port_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
3236 if (is_texture2d) {
3237 undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeTexture::SOURCE_PORT);
3238 }
3239 if (is_texture3d || is_texture2d_array) {
3240 undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeSample3D::SOURCE_PORT);
3241 }
3242 if (is_cubemap) {
3243 undo_redo->add_do_method(vsnode.ptr(), "set_source", VisualShaderNodeCubemap::SOURCE_PORT);
3244 }
3245 }
3246 }
3247 }
3248 _member_cancel();
3249
3250 if (is_parameter) {
3251 undo_redo->add_do_method(this, "_update_parameters", true);
3252 undo_redo->add_undo_method(this, "_update_parameters", true);
3253 }
3254
3255 if (is_curve) {
3256 graph_plugin->call_deferred(SNAME("update_curve"), id_to_use);
3257 }
3258
3259 if (is_curve_xyz) {
3260 graph_plugin->call_deferred(SNAME("update_curve_xyz"), id_to_use);
3261 }
3262
3263 if (p_resource_path.is_empty()) {
3264 undo_redo->commit_action();
3265 } else {
3266 //post-initialization
3267
3268 if (is_texture2d || is_texture3d || is_curve || is_curve_xyz) {
3269 undo_redo->add_do_method(vsnode.ptr(), "set_texture", ResourceLoader::load(p_resource_path));
3270 return;
3271 }
3272
3273 if (is_cubemap) {
3274 undo_redo->add_do_method(vsnode.ptr(), "set_cube_map", ResourceLoader::load(p_resource_path));
3275 return;
3276 }
3277
3278 if (is_texture2d_array) {
3279 undo_redo->add_do_method(vsnode.ptr(), "set_texture_array", ResourceLoader::load(p_resource_path));
3280 }
3281 }
3282}
3283
3284void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) {
3285 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3286 undo_redo->create_action(vformat(TTR("Add Varying to Visual Shader: %s"), p_name));
3287
3288 undo_redo->add_do_method(visual_shader.ptr(), "add_varying", p_name, p_mode, p_type);
3289 undo_redo->add_undo_method(visual_shader.ptr(), "remove_varying", p_name);
3290
3291 undo_redo->add_do_method(this, "_update_varyings");
3292 undo_redo->add_undo_method(this, "_update_varyings");
3293
3294 for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {
3295 if (p_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {
3296 continue;
3297 }
3298
3299 VisualShader::Type type = VisualShader::Type(i);
3300 Vector<int> nodes = visual_shader->get_node_list(type);
3301
3302 for (int j = 0; j < nodes.size(); j++) {
3303 int node_id = nodes[j];
3304 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
3305 Ref<VisualShaderNodeVarying> var = vsnode;
3306
3307 if (var.is_valid()) {
3308 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);
3309 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);
3310 }
3311 }
3312 }
3313
3314 undo_redo->add_do_method(this, "_update_varying_tree");
3315 undo_redo->add_undo_method(this, "_update_varying_tree");
3316 undo_redo->commit_action();
3317}
3318
3319void VisualShaderEditor::_remove_varying(const String &p_name) {
3320 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3321 undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name));
3322
3323 VisualShader::VaryingMode var_mode = visual_shader->get_varying_mode(p_name);
3324
3325 undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", p_name);
3326 undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", p_name, var_mode, visual_shader->get_varying_type(p_name));
3327
3328 undo_redo->add_do_method(this, "_update_varyings");
3329 undo_redo->add_undo_method(this, "_update_varyings");
3330
3331 for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {
3332 if (var_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {
3333 continue;
3334 }
3335
3336 VisualShader::Type type = VisualShader::Type(i);
3337 Vector<int> nodes = visual_shader->get_node_list(type);
3338
3339 for (int j = 0; j < nodes.size(); j++) {
3340 int node_id = nodes[j];
3341 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
3342 Ref<VisualShaderNodeVarying> var = vsnode;
3343
3344 if (var.is_valid()) {
3345 String var_name = var->get_varying_name();
3346
3347 if (var_name == p_name) {
3348 undo_redo->add_do_method(var.ptr(), "set_varying_name", "[None]");
3349 undo_redo->add_undo_method(var.ptr(), "set_varying_name", var_name);
3350 undo_redo->add_do_method(var.ptr(), "set_varying_type", VisualShader::VARYING_TYPE_FLOAT);
3351 undo_redo->add_undo_method(var.ptr(), "set_varying_type", var->get_varying_type());
3352 }
3353 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, node_id);
3354 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, node_id);
3355 }
3356 }
3357
3358 List<VisualShader::Connection> node_connections;
3359 visual_shader->get_node_connections(type, &node_connections);
3360
3361 for (VisualShader::Connection &E : node_connections) {
3362 Ref<VisualShaderNodeVaryingGetter> var_getter = Object::cast_to<VisualShaderNodeVaryingGetter>(visual_shader->get_node(type, E.from_node).ptr());
3363 if (var_getter.is_valid() && E.from_port > 0) {
3364 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3365 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3366 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3367 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3368 }
3369 Ref<VisualShaderNodeVaryingSetter> var_setter = Object::cast_to<VisualShaderNodeVaryingSetter>(visual_shader->get_node(type, E.to_node).ptr());
3370 if (var_setter.is_valid() && E.to_port > 0) {
3371 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3372 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3373 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3374 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3375 }
3376 }
3377 }
3378
3379 undo_redo->add_do_method(this, "_update_varying_tree");
3380 undo_redo->add_undo_method(this, "_update_varying_tree");
3381 undo_redo->commit_action();
3382}
3383
3384void VisualShaderEditor::_update_varyings() {
3385 VisualShaderNodeVarying::clear_varyings();
3386
3387 for (int i = 0; i < visual_shader->get_varyings_count(); i++) {
3388 const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);
3389
3390 if (var != nullptr) {
3391 VisualShaderNodeVarying::add_varying(var->name, var->mode, var->type);
3392 }
3393 }
3394}
3395
3396void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node) {
3397 VisualShader::Type type = get_current_shader_type();
3398 drag_buffer.push_back({ type, p_node, p_from, p_to });
3399 if (!drag_dirty) {
3400 call_deferred(SNAME("_nodes_dragged"));
3401 }
3402 drag_dirty = true;
3403}
3404
3405void VisualShaderEditor::_nodes_dragged() {
3406 drag_dirty = false;
3407
3408 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3409 undo_redo->create_action(TTR("Node(s) Moved"));
3410
3411 for (const DragOp &E : drag_buffer) {
3412 undo_redo->add_do_method(visual_shader.ptr(), "set_node_position", E.type, E.node, E.to);
3413 undo_redo->add_undo_method(visual_shader.ptr(), "set_node_position", E.type, E.node, E.from);
3414 undo_redo->add_do_method(graph_plugin.ptr(), "set_node_position", E.type, E.node, E.to);
3415 undo_redo->add_undo_method(graph_plugin.ptr(), "set_node_position", E.type, E.node, E.from);
3416 }
3417
3418 drag_buffer.clear();
3419 undo_redo->commit_action();
3420}
3421
3422void VisualShaderEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
3423 VisualShader::Type type = get_current_shader_type();
3424
3425 int from = p_from.to_int();
3426 int to = p_to.to_int();
3427
3428 if (!visual_shader->can_connect_nodes(type, from, p_from_index, to, p_to_index)) {
3429 return;
3430 }
3431
3432 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3433 undo_redo->create_action(TTR("Nodes Connected"));
3434
3435 List<VisualShader::Connection> conns;
3436 visual_shader->get_node_connections(type, &conns);
3437
3438 for (const VisualShader::Connection &E : conns) {
3439 if (E.to_node == to && E.to_port == p_to_index) {
3440 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3441 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3442 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3443 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3444 }
3445 }
3446
3447 undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
3448 undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
3449 undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
3450 undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
3451 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);
3452 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);
3453 undo_redo->commit_action();
3454}
3455
3456void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
3457 graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);
3458
3459 VisualShader::Type type = get_current_shader_type();
3460
3461 int from = p_from.to_int();
3462 int to = p_to.to_int();
3463
3464 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3465 undo_redo->create_action(TTR("Nodes Disconnected"));
3466 undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
3467 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
3468 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
3469 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
3470 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);
3471 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);
3472 undo_redo->commit_action();
3473}
3474
3475void VisualShaderEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
3476 from_node = p_from.to_int();
3477 from_slot = p_from_slot;
3478 VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;
3479 VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;
3480 Ref<VisualShaderNode> node = visual_shader->get_node(get_current_shader_type(), from_node);
3481 if (node.is_valid()) {
3482 output_port_type = node->get_output_port_type(from_slot);
3483 }
3484 _show_members_dialog(true, input_port_type, output_port_type);
3485}
3486
3487void VisualShaderEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {
3488 to_node = p_to.to_int();
3489 to_slot = p_to_slot;
3490 VisualShaderNode::PortType input_port_type = VisualShaderNode::PORT_TYPE_MAX;
3491 VisualShaderNode::PortType output_port_type = VisualShaderNode::PORT_TYPE_MAX;
3492 Ref<VisualShaderNode> node = visual_shader->get_node(get_current_shader_type(), to_node);
3493 if (node.is_valid()) {
3494 input_port_type = node->get_input_port_type(to_slot);
3495 }
3496 _show_members_dialog(true, input_port_type, output_port_type);
3497}
3498
3499void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
3500 VisualShader::Type type = VisualShader::Type(p_type);
3501 List<VisualShader::Connection> conns;
3502 visual_shader->get_node_connections(type, &conns);
3503
3504 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3505 for (const int &F : p_nodes) {
3506 for (const VisualShader::Connection &E : conns) {
3507 if (E.from_node == F || E.to_node == F) {
3508 undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3509 }
3510 }
3511 }
3512
3513 HashSet<String> parameter_names;
3514
3515 for (const int &F : p_nodes) {
3516 Ref<VisualShaderNode> node = visual_shader->get_node(type, F);
3517
3518 undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F);
3519 undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, F), F);
3520 undo_redo->add_undo_method(graph_plugin.ptr(), "add_node", type, F, false);
3521
3522 VisualShaderNodeParameter *parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
3523 if (parameter) {
3524 parameter_names.insert(parameter->get_parameter_name());
3525 }
3526 }
3527
3528 List<VisualShader::Connection> used_conns;
3529 for (const int &F : p_nodes) {
3530 for (const VisualShader::Connection &E : conns) {
3531 if (E.from_node == F || E.to_node == F) {
3532 bool cancel = false;
3533 for (List<VisualShader::Connection>::Element *R = used_conns.front(); R; R = R->next()) {
3534 if (R->get().from_node == E.from_node && R->get().from_port == E.from_port && R->get().to_node == E.to_node && R->get().to_port == E.to_port) {
3535 cancel = true; // to avoid ERR_ALREADY_EXISTS warning
3536 break;
3537 }
3538 }
3539 if (!cancel) {
3540 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3541 undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
3542 used_conns.push_back(E);
3543 }
3544 }
3545 }
3546 }
3547
3548 // Delete nodes from the graph.
3549 for (const int &F : p_nodes) {
3550 undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F, false);
3551 }
3552
3553 // Update parameter refs if any parameter has been deleted.
3554 if (parameter_names.size() > 0) {
3555 undo_redo->add_do_method(this, "_update_parameters", true);
3556 undo_redo->add_undo_method(this, "_update_parameters", true);
3557
3558 _update_parameter_refs(parameter_names);
3559 }
3560}
3561
3562void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to) {
3563 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3564 undo_redo->add_do_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_to);
3565 undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from);
3566}
3567
3568void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
3569 Ref<VisualShaderNode> node = visual_shader->get_node(p_type_id, p_node_id);
3570 ERR_FAIL_COND(!node.is_valid());
3571 ERR_FAIL_COND(!node->has_method("set_constant"));
3572 node->call("set_constant", p_var);
3573 if (p_preview_port != -1) {
3574 node->set_output_port_for_preview(p_preview_port);
3575 }
3576}
3577
3578void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
3579 Ref<VisualShaderNodeParameter> parameter = visual_shader->get_node(p_type_id, p_node_id);
3580 ERR_FAIL_COND(!parameter.is_valid());
3581
3582 String valid_name = visual_shader->validate_parameter_name(parameter->get_parameter_name(), parameter);
3583 parameter->set_parameter_name(valid_name);
3584 graph_plugin->set_parameter_name(p_type_id, p_node_id, valid_name);
3585
3586 if (parameter->has_method("set_default_value_enabled")) {
3587 parameter->call("set_default_value_enabled", true);
3588 parameter->call("set_default_value", p_var);
3589 }
3590 if (p_preview_port != -1) {
3591 parameter->set_output_port_for_preview(p_preview_port);
3592 }
3593}
3594
3595void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {
3596 VisualShader::Type type_id = get_current_shader_type();
3597
3598 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3599 if (!p_vice_versa) {
3600 undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));
3601 } else {
3602 undo_redo->create_action(TTR("Convert Parameter Node(s) To Constant(s)"));
3603 }
3604
3605 const HashSet<int> &current_set = p_vice_versa ? selected_parameters : selected_constants;
3606 HashSet<String> deleted_names;
3607
3608 for (const int &E : current_set) {
3609 int node_id = E;
3610 Ref<VisualShaderNode> node = visual_shader->get_node(type_id, node_id);
3611 bool caught = false;
3612 Variant var;
3613
3614 // float
3615 if (!p_vice_versa) {
3616 Ref<VisualShaderNodeFloatConstant> float_const = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());
3617 if (float_const.is_valid()) {
3618 _replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatParameter");
3619 var = float_const->get_constant();
3620 caught = true;
3621 }
3622 } else {
3623 Ref<VisualShaderNodeFloatParameter> float_parameter = Object::cast_to<VisualShaderNodeFloatParameter>(node.ptr());
3624 if (float_parameter.is_valid()) {
3625 _replace_node(type_id, node_id, "VisualShaderNodeFloatParameter", "VisualShaderNodeFloatConstant");
3626 var = float_parameter->get_default_value();
3627 caught = true;
3628 }
3629 }
3630
3631 // int
3632 if (!caught) {
3633 if (!p_vice_versa) {
3634 Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());
3635 if (int_const.is_valid()) {
3636 _replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntParameter");
3637 var = int_const->get_constant();
3638 caught = true;
3639 }
3640 } else {
3641 Ref<VisualShaderNodeIntParameter> int_parameter = Object::cast_to<VisualShaderNodeIntParameter>(node.ptr());
3642 if (int_parameter.is_valid()) {
3643 _replace_node(type_id, node_id, "VisualShaderNodeIntParameter", "VisualShaderNodeIntConstant");
3644 var = int_parameter->get_default_value();
3645 caught = true;
3646 }
3647 }
3648 }
3649
3650 // boolean
3651 if (!caught) {
3652 if (!p_vice_versa) {
3653 Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());
3654 if (boolean_const.is_valid()) {
3655 _replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanParameter");
3656 var = boolean_const->get_constant();
3657 caught = true;
3658 }
3659 } else {
3660 Ref<VisualShaderNodeBooleanParameter> boolean_parameter = Object::cast_to<VisualShaderNodeBooleanParameter>(node.ptr());
3661 if (boolean_parameter.is_valid()) {
3662 _replace_node(type_id, node_id, "VisualShaderNodeBooleanParameter", "VisualShaderNodeBooleanConstant");
3663 var = boolean_parameter->get_default_value();
3664 caught = true;
3665 }
3666 }
3667 }
3668
3669 // vec2
3670 if (!caught) {
3671 if (!p_vice_versa) {
3672 Ref<VisualShaderNodeVec2Constant> vec2_const = Object::cast_to<VisualShaderNodeVec2Constant>(node.ptr());
3673 if (vec2_const.is_valid()) {
3674 _replace_node(type_id, node_id, "VisualShaderNodeVec2Constant", "VisualShaderNodeVec2Parameter");
3675 var = vec2_const->get_constant();
3676 caught = true;
3677 }
3678 } else {
3679 Ref<VisualShaderNodeVec2Parameter> vec2_parameter = Object::cast_to<VisualShaderNodeVec2Parameter>(node.ptr());
3680 if (vec2_parameter.is_valid()) {
3681 _replace_node(type_id, node_id, "VisualShaderNodeVec2Parameter", "VisualShaderNodeVec2Constant");
3682 var = vec2_parameter->get_default_value();
3683 caught = true;
3684 }
3685 }
3686 }
3687
3688 // vec3
3689 if (!caught) {
3690 if (!p_vice_versa) {
3691 Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());
3692 if (vec3_const.is_valid()) {
3693 _replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Parameter");
3694 var = vec3_const->get_constant();
3695 caught = true;
3696 }
3697 } else {
3698 Ref<VisualShaderNodeVec3Parameter> vec3_parameter = Object::cast_to<VisualShaderNodeVec3Parameter>(node.ptr());
3699 if (vec3_parameter.is_valid()) {
3700 _replace_node(type_id, node_id, "VisualShaderNodeVec3Parameter", "VisualShaderNodeVec3Constant");
3701 var = vec3_parameter->get_default_value();
3702 caught = true;
3703 }
3704 }
3705 }
3706
3707 // vec4
3708 if (!caught) {
3709 if (!p_vice_versa) {
3710 Ref<VisualShaderNodeVec4Constant> vec4_const = Object::cast_to<VisualShaderNodeVec4Constant>(node.ptr());
3711 if (vec4_const.is_valid()) {
3712 _replace_node(type_id, node_id, "VisualShaderNodeVec4Constant", "VisualShaderNodeVec4Parameter");
3713 var = vec4_const->get_constant();
3714 caught = true;
3715 }
3716 } else {
3717 Ref<VisualShaderNodeVec4Parameter> vec4_parameter = Object::cast_to<VisualShaderNodeVec4Parameter>(node.ptr());
3718 if (vec4_parameter.is_valid()) {
3719 _replace_node(type_id, node_id, "VisualShaderNodeVec4Parameter", "VisualShaderNodeVec4Constant");
3720 var = vec4_parameter->get_default_value();
3721 caught = true;
3722 }
3723 }
3724 }
3725
3726 // color
3727 if (!caught) {
3728 if (!p_vice_versa) {
3729 Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());
3730 if (color_const.is_valid()) {
3731 _replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorParameter");
3732 var = color_const->get_constant();
3733 caught = true;
3734 }
3735 } else {
3736 Ref<VisualShaderNodeColorParameter> color_parameter = Object::cast_to<VisualShaderNodeColorParameter>(node.ptr());
3737 if (color_parameter.is_valid()) {
3738 _replace_node(type_id, node_id, "VisualShaderNodeColorParameter", "VisualShaderNodeColorConstant");
3739 var = color_parameter->get_default_value();
3740 caught = true;
3741 }
3742 }
3743 }
3744
3745 // transform
3746 if (!caught) {
3747 if (!p_vice_versa) {
3748 Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());
3749 if (transform_const.is_valid()) {
3750 _replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformParameter");
3751 var = transform_const->get_constant();
3752 caught = true;
3753 }
3754 } else {
3755 Ref<VisualShaderNodeTransformParameter> transform_parameter = Object::cast_to<VisualShaderNodeTransformParameter>(node.ptr());
3756 if (transform_parameter.is_valid()) {
3757 _replace_node(type_id, node_id, "VisualShaderNodeTransformParameter", "VisualShaderNodeTransformConstant");
3758 var = transform_parameter->get_default_value();
3759 caught = true;
3760 }
3761 }
3762 }
3763 ERR_CONTINUE(!caught);
3764 int preview_port = node->get_output_port_for_preview();
3765
3766 if (!p_vice_versa) {
3767 undo_redo->add_do_method(this, "_update_parameter", type_id, node_id, var, preview_port);
3768 undo_redo->add_undo_method(this, "_update_constant", type_id, node_id, var, preview_port);
3769 } else {
3770 undo_redo->add_do_method(this, "_update_constant", type_id, node_id, var, preview_port);
3771 undo_redo->add_undo_method(this, "_update_parameter", type_id, node_id, var, preview_port);
3772
3773 Ref<VisualShaderNodeParameter> parameter = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
3774 ERR_CONTINUE(!parameter.is_valid());
3775
3776 deleted_names.insert(parameter->get_parameter_name());
3777 }
3778
3779 undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, node_id);
3780 undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, node_id);
3781 }
3782
3783 undo_redo->add_do_method(this, "_update_parameters", true);
3784 undo_redo->add_undo_method(this, "_update_parameters", true);
3785
3786 if (deleted_names.size() > 0) {
3787 _update_parameter_refs(deleted_names);
3788 }
3789
3790 undo_redo->commit_action();
3791}
3792
3793void VisualShaderEditor::_close_node_request(int p_type, int p_node) {
3794 Ref<VisualShaderNode> node = visual_shader->get_node((VisualShader::Type)p_type, p_node);
3795 if (!node->is_closable()) {
3796 return;
3797 }
3798
3799 List<int> to_erase;
3800 to_erase.push_back(p_node);
3801
3802 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3803 undo_redo->create_action(TTR("Delete VisualShader Node"));
3804 _delete_nodes(p_type, to_erase);
3805 undo_redo->commit_action();
3806}
3807
3808void VisualShaderEditor::_close_nodes_request(const TypedArray<StringName> &p_nodes) {
3809 List<int> to_erase;
3810
3811 if (p_nodes.is_empty()) {
3812 // Called from context menu.
3813 for (int i = 0; i < graph->get_child_count(); i++) {
3814 GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));
3815 if (graph_element && graph_element->is_selected()) {
3816 VisualShader::Type type = get_current_shader_type();
3817 int id = String(graph_element->get_name()).to_int();
3818 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);
3819 if (vsnode->is_closable()) {
3820 to_erase.push_back(graph_element->get_name().operator String().to_int());
3821 }
3822 }
3823 }
3824 } else {
3825 VisualShader::Type type = get_current_shader_type();
3826 for (int i = 0; i < p_nodes.size(); i++) {
3827 int id = p_nodes[i].operator String().to_int();
3828 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);
3829 if (vsnode->is_closable()) {
3830 to_erase.push_back(id);
3831 }
3832 }
3833 }
3834
3835 if (to_erase.is_empty()) {
3836 return;
3837 }
3838
3839 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
3840 undo_redo->create_action(TTR("Delete VisualShader Node(s)"));
3841 _delete_nodes(get_current_shader_type(), to_erase);
3842 undo_redo->commit_action();
3843}
3844
3845void VisualShaderEditor::_node_selected(Object *p_node) {
3846 VisualShader::Type type = get_current_shader_type();
3847
3848 GraphElement *graph_element = Object::cast_to<GraphElement>(p_node);
3849 ERR_FAIL_NULL(graph_element);
3850
3851 int id = String(graph_element->get_name()).to_int();
3852
3853 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);
3854 ERR_FAIL_COND(!vsnode.is_valid());
3855}
3856
3857void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
3858 Ref<InputEventMouseButton> mb = p_event;
3859 VisualShader::Type type = get_current_shader_type();
3860
3861 Ref<VisualShaderNode> selected_vsnode;
3862 // Right click actions.
3863 if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
3864 selected_constants.clear();
3865 selected_parameters.clear();
3866 selected_comment = -1;
3867 selected_float_constant = -1;
3868
3869 List<int> selected_closable_graph_elements;
3870 for (int i = 0; i < graph->get_child_count(); i++) {
3871 GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));
3872 if (graph_element && graph_element->is_selected()) {
3873 int id = String(graph_element->get_name()).to_int();
3874 Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, id);
3875 if (!vsnode->is_closable()) {
3876 continue;
3877 }
3878
3879 selected_closable_graph_elements.push_back(id);
3880
3881 Ref<VisualShaderNode> node = visual_shader->get_node(type, id);
3882 selected_vsnode = node;
3883
3884 VisualShaderNodeComment *frame_node = Object::cast_to<VisualShaderNodeComment>(node.ptr());
3885 if (frame_node != nullptr) {
3886 selected_comment = id;
3887 }
3888 VisualShaderNodeConstant *constant_node = Object::cast_to<VisualShaderNodeConstant>(node.ptr());
3889 if (constant_node != nullptr) {
3890 selected_constants.insert(id);
3891 }
3892 VisualShaderNodeFloatConstant *float_constant_node = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());
3893 if (float_constant_node != nullptr) {
3894 selected_float_constant = id;
3895 }
3896 VisualShaderNodeParameter *parameter_node = Object::cast_to<VisualShaderNodeParameter>(node.ptr());
3897 if (parameter_node != nullptr && parameter_node->is_convertible_to_constant()) {
3898 selected_parameters.insert(id);
3899 }
3900 }
3901 }
3902
3903 if (selected_closable_graph_elements.size() > 1) {
3904 selected_comment = -1;
3905 selected_float_constant = -1;
3906 }
3907
3908 bool copy_buffer_empty = true;
3909 for (const CopyItem &item : copy_items_buffer) {
3910 if (!item.disabled) {
3911 copy_buffer_empty = false;
3912 break;
3913 }
3914 }
3915
3916 if (selected_closable_graph_elements.is_empty() && copy_buffer_empty) {
3917 _show_members_dialog(true);
3918 } else {
3919 popup_menu->set_item_disabled(NodeMenuOptions::CUT, selected_closable_graph_elements.is_empty());
3920 popup_menu->set_item_disabled(NodeMenuOptions::COPY, selected_closable_graph_elements.is_empty());
3921 popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_buffer_empty);
3922 popup_menu->set_item_disabled(NodeMenuOptions::DELETE, selected_closable_graph_elements.is_empty());
3923 popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, selected_closable_graph_elements.is_empty());
3924 popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_buffer_empty);
3925
3926 int temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR2);
3927 if (temp != -1) {
3928 popup_menu->remove_item(temp);
3929 }
3930 temp = popup_menu->get_item_index(NodeMenuOptions::FLOAT_CONSTANTS);
3931 if (temp != -1) {
3932 popup_menu->remove_item(temp);
3933 }
3934 temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
3935 if (temp != -1) {
3936 popup_menu->remove_item(temp);
3937 }
3938 temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
3939 if (temp != -1) {
3940 popup_menu->remove_item(temp);
3941 }
3942 temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR3);
3943 if (temp != -1) {
3944 popup_menu->remove_item(temp);
3945 }
3946 temp = popup_menu->get_item_index(NodeMenuOptions::SET_COMMENT_TITLE);
3947 if (temp != -1) {
3948 popup_menu->remove_item(temp);
3949 }
3950 temp = popup_menu->get_item_index(NodeMenuOptions::SET_COMMENT_DESCRIPTION);
3951 if (temp != -1) {
3952 popup_menu->remove_item(temp);
3953 }
3954
3955 if (selected_constants.size() > 0 || selected_parameters.size() > 0) {
3956 popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
3957
3958 if (selected_float_constant != -1) {
3959 popup_menu->add_submenu_item(TTR("Float Constants"), "FloatConstants", int(NodeMenuOptions::FLOAT_CONSTANTS));
3960
3961 if (!constants_submenu) {
3962 constants_submenu = memnew(PopupMenu);
3963 constants_submenu->set_name("FloatConstants");
3964
3965 for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {
3966 constants_submenu->add_item(float_constant_defs[i].name, i);
3967 }
3968 popup_menu->add_child(constants_submenu);
3969 constants_submenu->connect("index_pressed", callable_mp(this, &VisualShaderEditor::_float_constant_selected));
3970 }
3971 }
3972
3973 if (selected_constants.size() > 0) {
3974 popup_menu->add_item(TTR("Convert Constant(s) to Parameter(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS);
3975 }
3976
3977 if (selected_parameters.size() > 0) {
3978 popup_menu->add_item(TTR("Convert Parameter(s) to Constant(s)"), NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS);
3979 }
3980 }
3981
3982 if (selected_comment != -1) {
3983 popup_menu->add_separator("", NodeMenuOptions::SEPARATOR3);
3984 popup_menu->add_item(TTR("Set Comment Title"), NodeMenuOptions::SET_COMMENT_TITLE);
3985 popup_menu->add_item(TTR("Set Comment Description"), NodeMenuOptions::SET_COMMENT_DESCRIPTION);
3986 }
3987
3988 menu_point = graph->get_local_mouse_position();
3989 Point2 gpos = get_screen_position() + get_local_mouse_position();
3990 popup_menu->set_position(gpos);
3991 popup_menu->reset_size();
3992 popup_menu->popup();
3993 }
3994 }
3995}
3996
3997void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNode::PortType p_input_port_type, VisualShaderNode::PortType p_output_port_type) {
3998 if (members_input_port_type != p_input_port_type || members_output_port_type != p_output_port_type) {
3999 members_input_port_type = p_input_port_type;
4000 members_output_port_type = p_output_port_type;
4001 _update_options_menu();
4002 }
4003
4004 if (at_mouse_pos) {
4005 saved_node_pos_dirty = true;
4006 saved_node_pos = graph->get_local_mouse_position();
4007
4008 Point2 gpos = get_screen_position() + get_local_mouse_position();
4009 members_dialog->set_position(gpos);
4010 } else {
4011 saved_node_pos_dirty = false;
4012 members_dialog->set_position(graph->get_screen_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
4013 }
4014 members_dialog->popup();
4015
4016 // Keep dialog within window bounds.
4017 Rect2 window_rect = Rect2(get_window()->get_position(), get_window()->get_size());
4018 Rect2 dialog_rect = Rect2(members_dialog->get_position(), members_dialog->get_size());
4019 Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2());
4020 members_dialog->set_position(members_dialog->get_position() - difference);
4021
4022 node_filter->call_deferred(SNAME("grab_focus")); // Still not visible.
4023 node_filter->select_all();
4024}
4025
4026void VisualShaderEditor::_varying_menu_id_pressed(int p_idx) {
4027 switch (VaryingMenuOptions(p_idx)) {
4028 case VaryingMenuOptions::ADD: {
4029 _show_add_varying_dialog();
4030 } break;
4031 case VaryingMenuOptions::REMOVE: {
4032 _show_remove_varying_dialog();
4033 } break;
4034 default:
4035 break;
4036 }
4037}
4038
4039void VisualShaderEditor::_show_add_varying_dialog() {
4040 _varying_name_changed(varying_name->get_text());
4041
4042 add_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
4043 add_varying_dialog->popup();
4044
4045 // Keep dialog within window bounds.
4046 Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());
4047 Rect2 dialog_rect = Rect2(add_varying_dialog->get_position(), add_varying_dialog->get_size());
4048 Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2());
4049 add_varying_dialog->set_position(add_varying_dialog->get_position() - difference);
4050}
4051
4052void VisualShaderEditor::_show_remove_varying_dialog() {
4053 remove_varying_dialog->set_position(graph->get_screen_position() + varying_button->get_position() + Point2(5 * EDSCALE, 65 * EDSCALE));
4054 remove_varying_dialog->popup();
4055
4056 // Keep dialog within window bounds.
4057 Rect2 window_rect = Rect2(DisplayServer::get_singleton()->window_get_position(), DisplayServer::get_singleton()->window_get_size());
4058 Rect2 dialog_rect = Rect2(remove_varying_dialog->get_position(), remove_varying_dialog->get_size());
4059 Vector2 difference = (dialog_rect.get_end() - window_rect.get_end()).max(Vector2());
4060 remove_varying_dialog->set_position(remove_varying_dialog->get_position() - difference);
4061}
4062
4063void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
4064 Ref<InputEventKey> ie = p_ie;
4065 if (ie.is_valid() && (ie->get_keycode() == Key::UP || ie->get_keycode() == Key::DOWN || ie->get_keycode() == Key::ENTER || ie->get_keycode() == Key::KP_ENTER)) {
4066 members->gui_input(ie);
4067 node_filter->accept_event();
4068 }
4069}
4070
4071void VisualShaderEditor::_notification(int p_what) {
4072 switch (p_what) {
4073 case NOTIFICATION_POSTINITIALIZE: {
4074 _update_options_menu();
4075 } break;
4076
4077 case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
4078 graph->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")));
4079 graph->set_warped_panning(bool(EDITOR_GET("editors/panning/warped_mouse_panning")));
4080 graph->set_minimap_opacity(EDITOR_GET("editors/visual_editors/minimap_opacity"));
4081 graph->set_connection_lines_curvature(EDITOR_GET("editors/visual_editors/lines_curvature"));
4082 _update_graph();
4083 } break;
4084
4085 case NOTIFICATION_ENTER_TREE: {
4086 node_filter->set_clear_button_enabled(true);
4087
4088 // collapse tree by default
4089
4090 TreeItem *category = members->get_root()->get_first_child();
4091 while (category) {
4092 category->set_collapsed(true);
4093 TreeItem *sub_category = category->get_first_child();
4094 while (sub_category) {
4095 sub_category->set_collapsed(true);
4096 sub_category = sub_category->get_next();
4097 }
4098 category = category->get_next();
4099 }
4100
4101 graph->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")));
4102 graph->set_warped_panning(bool(EDITOR_GET("editors/panning/warped_mouse_panning")));
4103 } break;
4104
4105 case NOTIFICATION_THEME_CHANGED: {
4106 highend_label->set_modulate(get_theme_color(SNAME("highend_color"), EditorStringName(Editor)));
4107
4108 node_filter->set_right_icon(Control::get_editor_theme_icon(SNAME("Search")));
4109
4110 preview_shader->set_icon(Control::get_editor_theme_icon(SNAME("Shader")));
4111
4112 {
4113 Color background_color = EDITOR_GET("text_editor/theme/highlighting/background_color");
4114 Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");
4115 Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
4116 Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
4117 Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
4118 Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");
4119 Color function_color = EDITOR_GET("text_editor/theme/highlighting/function_color");
4120 Color number_color = EDITOR_GET("text_editor/theme/highlighting/number_color");
4121 Color members_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
4122 Color error_color = get_theme_color(SNAME("error_color"), EditorStringName(Editor));
4123
4124 preview_text->add_theme_color_override("background_color", background_color);
4125 varying_error_label->add_theme_color_override("font_color", error_color);
4126
4127 for (const String &E : keyword_list) {
4128 if (ShaderLanguage::is_control_flow_keyword(E)) {
4129 syntax_highlighter->add_keyword_color(E, control_flow_keyword_color);
4130 } else {
4131 syntax_highlighter->add_keyword_color(E, keyword_color);
4132 }
4133 }
4134
4135 preview_text->add_theme_font_override("font", get_theme_font(SNAME("expression"), EditorStringName(EditorFonts)));
4136 preview_text->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("expression_size"), EditorStringName(EditorFonts)));
4137 preview_text->add_theme_color_override("font_color", text_color);
4138 syntax_highlighter->set_number_color(number_color);
4139 syntax_highlighter->set_symbol_color(symbol_color);
4140 syntax_highlighter->set_function_color(function_color);
4141 syntax_highlighter->set_member_variable_color(members_color);
4142 syntax_highlighter->clear_color_regions();
4143 syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
4144 syntax_highlighter->add_color_region("//", "", comment_color, true);
4145
4146 preview_text->clear_comment_delimiters();
4147 preview_text->add_comment_delimiter("/*", "*/", false);
4148 preview_text->add_comment_delimiter("//", "", true);
4149
4150 error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
4151 error_label->add_theme_font_override("font", get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts)));
4152 error_label->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("status_source_size"), EditorStringName(EditorFonts)));
4153 error_label->add_theme_color_override("font_color", error_color);
4154 }
4155
4156 tools->set_icon(get_editor_theme_icon(SNAME("Tools")));
4157
4158 if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) {
4159 _update_graph();
4160 }
4161 } break;
4162
4163 case NOTIFICATION_DRAG_BEGIN: {
4164 Dictionary dd = get_viewport()->gui_get_drag_data();
4165 if (members->is_visible_in_tree() && dd.has("id")) {
4166 members->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
4167 }
4168 } break;
4169
4170 case NOTIFICATION_DRAG_END: {
4171 members->set_drop_mode_flags(0);
4172 } break;
4173 }
4174}
4175
4176void VisualShaderEditor::_scroll_changed(const Vector2 &p_scroll) {
4177 if (updating) {
4178 return;
4179 }
4180 updating = true;
4181 visual_shader->set_graph_offset(p_scroll / EDSCALE);
4182 updating = false;
4183}
4184
4185void VisualShaderEditor::_node_changed(int p_id) {
4186 if (updating) {
4187 return;
4188 }
4189
4190 if (is_visible_in_tree()) {
4191 _update_graph();
4192 }
4193}
4194
4195void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, List<VisualShader::Connection> &r_connections) {
4196 VisualShader::Type type = (VisualShader::Type)p_type;
4197
4198 selection_center.x = 0.0f;
4199 selection_center.y = 0.0f;
4200
4201 HashSet<int> nodes;
4202
4203 for (int i = 0; i < graph->get_child_count(); i++) {
4204 GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));
4205 if (graph_element) {
4206 int id = String(graph_element->get_name()).to_int();
4207
4208 Ref<VisualShaderNode> node = visual_shader->get_node(type, id);
4209 Ref<VisualShaderNodeOutput> output = node;
4210 if (output.is_valid()) { // can't duplicate output
4211 continue;
4212 }
4213
4214 if (node.is_valid() && graph_element->is_selected()) {
4215 Vector2 pos = visual_shader->get_node_position(type, id);
4216 selection_center += pos;
4217
4218 CopyItem item;
4219 item.id = id;
4220 item.node = visual_shader->get_node(type, id)->duplicate();
4221 item.position = visual_shader->get_node_position(type, id);
4222
4223 Ref<VisualShaderNodeResizableBase> resizable_base = node;
4224 if (resizable_base.is_valid()) {
4225 item.size = resizable_base->get_size();
4226 }
4227
4228 Ref<VisualShaderNodeGroupBase> group = node;
4229 if (group.is_valid()) {
4230 item.group_inputs = group->get_inputs();
4231 item.group_outputs = group->get_outputs();
4232 }
4233
4234 Ref<VisualShaderNodeExpression> expression = node;
4235 if (expression.is_valid()) {
4236 item.expression = expression->get_expression();
4237 }
4238
4239 r_items.push_back(item);
4240
4241 nodes.insert(id);
4242 }
4243 }
4244 }
4245
4246 List<VisualShader::Connection> node_connections;
4247 visual_shader->get_node_connections(type, &node_connections);
4248
4249 for (const VisualShader::Connection &E : node_connections) {
4250 if (nodes.has(E.from_node) && nodes.has(E.to_node)) {
4251 r_connections.push_back(E);
4252 }
4253 }
4254
4255 selection_center /= (float)r_items.size();
4256}
4257
4258void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate) {
4259 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
4260 if (p_duplicate) {
4261 undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));
4262 } else {
4263 bool copy_buffer_empty = true;
4264 for (const CopyItem &item : copy_items_buffer) {
4265 if (!item.disabled) {
4266 copy_buffer_empty = false;
4267 break;
4268 }
4269 }
4270 if (copy_buffer_empty) {
4271 return;
4272 }
4273
4274 undo_redo->create_action(TTR("Paste VisualShader Node(s)"));
4275 }
4276
4277 VisualShader::Type type = (VisualShader::Type)p_type;
4278
4279 int base_id = visual_shader->get_valid_node_id(type);
4280 int id_from = base_id;
4281 HashMap<int, int> connection_remap;
4282 HashSet<int> unsupported_set;
4283 HashSet<int> added_set;
4284
4285 for (CopyItem &item : r_items) {
4286 if (item.disabled) {
4287 unsupported_set.insert(item.id);
4288 continue;
4289 }
4290 connection_remap[item.id] = id_from;
4291 Ref<VisualShaderNode> node = item.node->duplicate();
4292
4293 Ref<VisualShaderNodeResizableBase> resizable_base = Object::cast_to<VisualShaderNodeResizableBase>(node.ptr());
4294 if (resizable_base.is_valid()) {
4295 undo_redo->add_do_method(node.ptr(), "set_size", item.size);
4296 }
4297
4298 Ref<VisualShaderNodeGroupBase> group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
4299 if (group.is_valid()) {
4300 undo_redo->add_do_method(node.ptr(), "set_inputs", item.group_inputs);
4301 undo_redo->add_do_method(node.ptr(), "set_outputs", item.group_outputs);
4302 }
4303
4304 Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
4305 if (expression.is_valid()) {
4306 undo_redo->add_do_method(node.ptr(), "set_expression", item.expression);
4307 }
4308
4309 undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, node, item.position + p_offset, id_from);
4310 undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_from, false);
4311
4312 added_set.insert(id_from);
4313 id_from++;
4314 }
4315
4316 for (const VisualShader::Connection &E : p_connections) {
4317 if (unsupported_set.has(E.from_node) || unsupported_set.has(E.to_node)) {
4318 continue;
4319 }
4320
4321 undo_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);
4322 undo_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);
4323 undo_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);
4324 }
4325
4326 id_from = base_id;
4327 for (const CopyItem &item : r_items) {
4328 if (item.disabled) {
4329 continue;
4330 }
4331 undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from);
4332 undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_from, false);
4333 id_from++;
4334 }
4335
4336 undo_redo->commit_action();
4337
4338 // reselect nodes by excluding the other ones
4339 for (int i = 0; i < graph->get_child_count(); i++) {
4340 GraphElement *graph_element = Object::cast_to<GraphElement>(graph->get_child(i));
4341 if (graph_element) {
4342 int id = String(graph_element->get_name()).to_int();
4343 if (added_set.has(id)) {
4344 graph_element->set_selected(true);
4345 } else {
4346 graph_element->set_selected(false);
4347 }
4348 }
4349 }
4350}
4351
4352void VisualShaderEditor::_clear_copy_buffer() {
4353 copy_items_buffer.clear();
4354 copy_connections_buffer.clear();
4355}
4356
4357void VisualShaderEditor::_duplicate_nodes() {
4358 int type = get_current_shader_type();
4359
4360 List<CopyItem> items;
4361 List<VisualShader::Connection> node_connections;
4362
4363 _dup_copy_nodes(type, items, node_connections);
4364
4365 if (items.is_empty()) {
4366 return;
4367 }
4368
4369 _dup_paste_nodes(type, items, node_connections, Vector2(10, 10) * EDSCALE, true);
4370}
4371
4372void VisualShaderEditor::_copy_nodes(bool p_cut) {
4373 _clear_copy_buffer();
4374
4375 _dup_copy_nodes(get_current_shader_type(), copy_items_buffer, copy_connections_buffer);
4376
4377 if (p_cut) {
4378 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
4379 undo_redo->create_action(TTR("Cut VisualShader Node(s)"));
4380
4381 List<int> ids;
4382 for (const CopyItem &E : copy_items_buffer) {
4383 ids.push_back(E.id);
4384 }
4385
4386 _delete_nodes(get_current_shader_type(), ids);
4387
4388 undo_redo->commit_action();
4389 }
4390}
4391
4392void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2 &p_custom_position) {
4393 if (copy_items_buffer.is_empty()) {
4394 return;
4395 }
4396
4397 int type = get_current_shader_type();
4398
4399 float scale = graph->get_zoom();
4400
4401 Vector2 mpos;
4402 if (p_use_custom_position) {
4403 mpos = p_custom_position;
4404 } else {
4405 mpos = graph->get_local_mouse_position();
4406 }
4407
4408 _dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_offset() / scale + mpos / scale - selection_center, false);
4409}
4410
4411void VisualShaderEditor::_mode_selected(int p_id) {
4412 int offset = 0;
4413 if (mode & MODE_FLAGS_PARTICLES) {
4414 offset = 3;
4415 if (p_id + offset > VisualShader::TYPE_PROCESS) {
4416 custom_mode_box->set_visible(false);
4417 custom_mode_enabled = false;
4418 } else {
4419 custom_mode_box->set_visible(true);
4420 if (custom_mode_box->is_pressed()) {
4421 custom_mode_enabled = true;
4422 offset += 3;
4423 }
4424 }
4425 } else if (mode & MODE_FLAGS_SKY) {
4426 offset = 8;
4427 } else if (mode & MODE_FLAGS_FOG) {
4428 offset = 9;
4429 }
4430
4431 visual_shader->set_shader_type(VisualShader::Type(p_id + offset));
4432 _update_nodes();
4433 _update_graph();
4434
4435 graph->grab_focus();
4436}
4437
4438void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) {
4439 if (!(mode & MODE_FLAGS_PARTICLES)) {
4440 return;
4441 }
4442 custom_mode_enabled = p_enabled;
4443 int id = edit_type->get_selected() + 3;
4444 if (p_enabled) {
4445 visual_shader->set_shader_type(VisualShader::Type(id + 3));
4446 } else {
4447 visual_shader->set_shader_type(VisualShader::Type(id));
4448 }
4449 _update_options_menu();
4450 _update_graph();
4451}
4452
4453void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, String p_name) {
4454 String prev_name = p_input->get_input_name();
4455
4456 if (p_name == prev_name) {
4457 return;
4458 }
4459
4460 VisualShaderNode::PortType next_input_type = p_input->get_input_type_by_name(p_name);
4461 VisualShaderNode::PortType prev_input_type = p_input->get_input_type_by_name(prev_name);
4462
4463 bool type_changed = next_input_type != prev_input_type;
4464
4465 EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
4466 undo_redo_man->create_action(TTR("Visual Shader Input Type Changed"));
4467
4468 undo_redo_man->add_do_method(p_input.ptr(), "set_input_name", p_name);
4469 undo_redo_man->add_undo_method(p_input.ptr(), "set_input_name", prev_name);
4470
4471 if (type_changed) {
4472 for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
4473 VisualShader::Type type = VisualShader::Type(type_id);
4474
4475 int id = visual_shader->find_node_id(type, p_input);
4476 if (id != VisualShader::NODE_ID_INVALID) {
4477 bool is_expanded = p_input->is_output_port_expandable(0) && p_input->_is_output_port_expanded(0);
4478
4479 int type_size = 0;
4480 if (is_expanded) {
4481 switch (next_input_type) {
4482 case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
4483 type_size = 2;
4484 } break;
4485 case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
4486 type_size = 3;
4487 } break;
4488 case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
4489 type_size = 4;
4490 } break;
4491 default:
4492 break;
4493 }
4494 }
4495
4496 List<VisualShader::Connection> conns;
4497 visual_shader->get_node_connections(type, &conns);
4498 for (const VisualShader::Connection &E : conns) {
4499 int cn_from_node = E.from_node;
4500 int cn_from_port = E.from_port;
4501 int cn_to_node = E.to_node;
4502 int cn_to_port = E.to_port;
4503
4504 if (cn_from_node == id) {
4505 bool 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));
4506
4507 if (is_incompatible_types || cn_from_port > type_size) {
4508 undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
4509 undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
4510 undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
4511 undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
4512 }
4513 }
4514 }
4515
4516 undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
4517 undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
4518 }
4519 }
4520 }
4521
4522 undo_redo_man->commit_action();
4523}
4524
4525void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name) {
4526 String prev_name = p_parameter_ref->get_parameter_name();
4527
4528 if (p_name == prev_name) {
4529 return;
4530 }
4531
4532 bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name);
4533
4534 EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
4535 undo_redo_man->create_action(TTR("ParameterRef Name Changed"));
4536
4537 undo_redo_man->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);
4538 undo_redo_man->add_undo_method(p_parameter_ref.ptr(), "set_parameter_name", prev_name);
4539
4540 // update output port
4541 for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
4542 VisualShader::Type type = VisualShader::Type(type_id);
4543 int id = visual_shader->find_node_id(type, p_parameter_ref);
4544 if (id != VisualShader::NODE_ID_INVALID) {
4545 if (type_changed) {
4546 List<VisualShader::Connection> conns;
4547 visual_shader->get_node_connections(type, &conns);
4548 for (const VisualShader::Connection &E : conns) {
4549 if (E.from_node == id) {
4550 if (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))) {
4551 continue;
4552 }
4553 undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4554 undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4555 undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4556 undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4557 }
4558 }
4559 }
4560 undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
4561 undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
4562 break;
4563 }
4564 }
4565
4566 undo_redo_man->commit_action();
4567}
4568
4569void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name) {
4570 String prev_name = p_varying->get_varying_name();
4571
4572 if (p_name == prev_name) {
4573 return;
4574 }
4575
4576 bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
4577
4578 EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
4579 undo_redo_man->create_action(TTR("Varying Name Changed"));
4580
4581 undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
4582 undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_name", prev_name);
4583
4584 VisualShader::VaryingType vtype = p_varying->get_varying_type_by_name(p_name);
4585 VisualShader::VaryingType prev_vtype = p_varying->get_varying_type_by_name(prev_name);
4586
4587 bool type_changed = vtype != prev_vtype;
4588
4589 if (type_changed) {
4590 undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_type", vtype);
4591 undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_type", prev_vtype);
4592 }
4593
4594 // update ports
4595 for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
4596 VisualShader::Type type = VisualShader::Type(type_id);
4597 int id = visual_shader->find_node_id(type, p_varying);
4598
4599 if (id != VisualShader::NODE_ID_INVALID) {
4600 if (type_changed) {
4601 List<VisualShader::Connection> conns;
4602 visual_shader->get_node_connections(type, &conns);
4603
4604 for (const VisualShader::Connection &E : conns) {
4605 if (is_getter) {
4606 if (E.from_node == id) {
4607 if (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))) {
4608 continue;
4609 }
4610 undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4611 undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4612 undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4613 undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4614 }
4615 } else {
4616 if (E.to_node == id) {
4617 if (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))) {
4618 continue;
4619 }
4620 undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4621 undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4622 undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4623 undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
4624 }
4625 }
4626 }
4627 }
4628
4629 undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
4630 undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
4631 break;
4632 }
4633 }
4634
4635 undo_redo_man->commit_action();
4636}
4637
4638void VisualShaderEditor::_float_constant_selected(int p_which) {
4639 ERR_FAIL_INDEX(p_which, MAX_FLOAT_CONST_DEFS);
4640
4641 VisualShader::Type type = get_current_shader_type();
4642 Ref<VisualShaderNodeFloatConstant> node = visual_shader->get_node(type, selected_float_constant);
4643 ERR_FAIL_COND(!node.is_valid());
4644
4645 if (Math::is_equal_approx(node->get_constant(), float_constant_defs[p_which].value)) {
4646 return; // same
4647 }
4648
4649 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
4650 undo_redo->create_action(vformat(TTR("Set Constant: %s"), float_constant_defs[p_which].name));
4651 undo_redo->add_do_method(node.ptr(), "set_constant", float_constant_defs[p_which].value);
4652 undo_redo->add_undo_method(node.ptr(), "set_constant", node->get_constant());
4653 undo_redo->commit_action();
4654}
4655
4656void VisualShaderEditor::_member_filter_changed(const String &p_text) {
4657 _update_options_menu();
4658}
4659
4660void VisualShaderEditor::_member_selected() {
4661 TreeItem *item = members->get_selected();
4662
4663 if (item != nullptr && item->has_meta("id")) {
4664 members_dialog->get_ok_button()->set_disabled(false);
4665 highend_label->set_visible(add_options[item->get_meta("id")].highend);
4666 node_desc->set_text(_get_description(item->get_meta("id")));
4667 } else {
4668 highend_label->set_visible(false);
4669 members_dialog->get_ok_button()->set_disabled(true);
4670 node_desc->set_text("");
4671 }
4672}
4673
4674void VisualShaderEditor::_member_unselected() {
4675}
4676
4677void VisualShaderEditor::_member_create() {
4678 TreeItem *item = members->get_selected();
4679 if (item != nullptr && item->has_meta("id")) {
4680 int idx = members->get_selected()->get_meta("id");
4681 _add_node(idx, add_options[idx].ops);
4682 members_dialog->hide();
4683 }
4684}
4685
4686void VisualShaderEditor::_member_cancel() {
4687 to_node = -1;
4688 to_slot = -1;
4689 from_node = -1;
4690 from_slot = -1;
4691}
4692
4693void VisualShaderEditor::_update_varying_tree() {
4694 varyings->clear();
4695 TreeItem *root = varyings->create_item();
4696
4697 int count = visual_shader->get_varyings_count();
4698
4699 for (int i = 0; i < count; i++) {
4700 const VisualShader::Varying *varying = visual_shader->get_varying_by_index(i);
4701
4702 if (varying) {
4703 TreeItem *item = varyings->create_item(root);
4704 item->set_text(0, varying->name);
4705
4706 if (i == 0) {
4707 item->select(0);
4708 }
4709
4710 switch (varying->type) {
4711 case VisualShader::VARYING_TYPE_FLOAT:
4712 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)));
4713 break;
4714 case VisualShader::VARYING_TYPE_INT:
4715 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)));
4716 break;
4717 case VisualShader::VARYING_TYPE_UINT:
4718 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)));
4719 break;
4720 case VisualShader::VARYING_TYPE_VECTOR_2D:
4721 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)));
4722 break;
4723 case VisualShader::VARYING_TYPE_VECTOR_3D:
4724 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)));
4725 break;
4726 case VisualShader::VARYING_TYPE_VECTOR_4D:
4727 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)));
4728 break;
4729 case VisualShader::VARYING_TYPE_BOOLEAN:
4730 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)));
4731 break;
4732 case VisualShader::VARYING_TYPE_TRANSFORM:
4733 item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)));
4734 break;
4735 default:
4736 break;
4737 }
4738 }
4739 }
4740
4741 varying_button->get_popup()->set_item_disabled(int(VaryingMenuOptions::REMOVE), count == 0);
4742}
4743
4744void VisualShaderEditor::_varying_create() {
4745 _add_varying(varying_name->get_text(), (VisualShader::VaryingMode)varying_mode->get_selected(), (VisualShader::VaryingType)varying_type->get_selected());
4746 add_varying_dialog->hide();
4747}
4748
4749void VisualShaderEditor::_varying_name_changed(const String &p_text) {
4750 String name = p_text;
4751
4752 if (!name.is_valid_identifier()) {
4753 varying_error_label->show();
4754 varying_error_label->set_text(TTR("Invalid name for varying."));
4755 add_varying_dialog->get_ok_button()->set_disabled(true);
4756 return;
4757 }
4758 if (visual_shader->has_varying(name)) {
4759 varying_error_label->show();
4760 varying_error_label->set_text(TTR("Varying with that name is already exist."));
4761 add_varying_dialog->get_ok_button()->set_disabled(true);
4762 return;
4763 }
4764 if (varying_error_label->is_visible()) {
4765 varying_error_label->hide();
4766 add_varying_dialog->set_size(Size2(add_varying_dialog->get_size().x, 0));
4767 }
4768 add_varying_dialog->get_ok_button()->set_disabled(false);
4769}
4770
4771void VisualShaderEditor::_varying_deleted() {
4772 TreeItem *item = varyings->get_selected();
4773
4774 if (item != nullptr) {
4775 _remove_varying(item->get_text(0));
4776 remove_varying_dialog->hide();
4777 }
4778}
4779
4780void VisualShaderEditor::_varying_selected() {
4781 add_varying_dialog->get_ok_button()->set_disabled(false);
4782}
4783
4784void VisualShaderEditor::_varying_unselected() {
4785 add_varying_dialog->get_ok_button()->set_disabled(true);
4786}
4787
4788void VisualShaderEditor::_tools_menu_option(int p_idx) {
4789 TreeItem *category = members->get_root()->get_first_child();
4790
4791 switch (p_idx) {
4792 case EXPAND_ALL:
4793
4794 while (category) {
4795 category->set_collapsed(false);
4796 TreeItem *sub_category = category->get_first_child();
4797 while (sub_category) {
4798 sub_category->set_collapsed(false);
4799 sub_category = sub_category->get_next();
4800 }
4801 category = category->get_next();
4802 }
4803
4804 break;
4805
4806 case COLLAPSE_ALL:
4807
4808 while (category) {
4809 category->set_collapsed(true);
4810 TreeItem *sub_category = category->get_first_child();
4811 while (sub_category) {
4812 sub_category->set_collapsed(true);
4813 sub_category = sub_category->get_next();
4814 }
4815 category = category->get_next();
4816 }
4817
4818 break;
4819 default:
4820 break;
4821 }
4822}
4823
4824void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
4825 switch (p_idx) {
4826 case NodeMenuOptions::ADD:
4827 _show_members_dialog(true);
4828 break;
4829 case NodeMenuOptions::CUT:
4830 _copy_nodes(true);
4831 break;
4832 case NodeMenuOptions::COPY:
4833 _copy_nodes(false);
4834 break;
4835 case NodeMenuOptions::PASTE:
4836 _paste_nodes(true, menu_point);
4837 break;
4838 case NodeMenuOptions::DELETE:
4839 _close_nodes_request(TypedArray<StringName>());
4840 break;
4841 case NodeMenuOptions::DUPLICATE:
4842 _duplicate_nodes();
4843 break;
4844 case NodeMenuOptions::CLEAR_COPY_BUFFER:
4845 _clear_copy_buffer();
4846 break;
4847 case NodeMenuOptions::CONVERT_CONSTANTS_TO_PARAMETERS:
4848 _convert_constants_to_parameters(false);
4849 break;
4850 case NodeMenuOptions::CONVERT_PARAMETERS_TO_CONSTANTS:
4851 _convert_constants_to_parameters(true);
4852 break;
4853 case NodeMenuOptions::SET_COMMENT_TITLE:
4854 _comment_title_popup_show(get_screen_position() + get_local_mouse_position(), selected_comment);
4855 break;
4856 case NodeMenuOptions::SET_COMMENT_DESCRIPTION:
4857 _comment_desc_popup_show(get_screen_position() + get_local_mouse_position(), selected_comment);
4858 break;
4859 default:
4860 break;
4861 }
4862}
4863
4864Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
4865 if (p_from == members) {
4866 TreeItem *it = members->get_item_at_position(p_point);
4867 if (!it) {
4868 return Variant();
4869 }
4870 if (!it->has_meta("id")) {
4871 return Variant();
4872 }
4873
4874 int id = it->get_meta("id");
4875 AddOption op = add_options[id];
4876
4877 Dictionary d;
4878 d["id"] = id;
4879
4880 Label *label = memnew(Label);
4881 label->set_text(it->get_text(0));
4882 set_drag_preview(label);
4883 return d;
4884 }
4885 return Variant();
4886}
4887
4888bool VisualShaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
4889 if (p_from == graph) {
4890 Dictionary d = p_data;
4891
4892 if (d.has("id")) {
4893 return true;
4894 }
4895 if (d.has("files")) {
4896 return true;
4897 }
4898 }
4899
4900 return false;
4901}
4902
4903void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
4904 if (p_from == graph) {
4905 Dictionary d = p_data;
4906
4907 if (d.has("id")) {
4908 int idx = d["id"];
4909 saved_node_pos = p_point;
4910 saved_node_pos_dirty = true;
4911 _add_node(idx, add_options[idx].ops);
4912 } else if (d.has("files")) {
4913 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
4914 undo_redo->create_action(TTR("Add Node(s) to Visual Shader"));
4915
4916 if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) {
4917 PackedStringArray arr = d["files"];
4918 for (int i = 0; i < arr.size(); i++) {
4919 String type = ResourceLoader::get_resource_type(arr[i]);
4920 if (type == "GDScript") {
4921 Ref<Script> scr = ResourceLoader::load(arr[i]);
4922 if (scr->get_instance_base_type() == "VisualShaderNodeCustom") {
4923 saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
4924 saved_node_pos_dirty = true;
4925
4926 int idx = -1;
4927
4928 for (int j = custom_node_option_idx; j < add_options.size(); j++) {
4929 if (add_options[j].script.is_valid()) {
4930 if (add_options[j].script->get_path() == arr[i]) {
4931 idx = j;
4932 break;
4933 }
4934 }
4935 }
4936 if (idx != -1) {
4937 _add_node(idx, {}, arr[i], i);
4938 }
4939 }
4940 } else if (type == "CurveTexture") {
4941 saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
4942 saved_node_pos_dirty = true;
4943 _add_node(curve_node_option_idx, {}, arr[i], i);
4944 } else if (type == "CurveXYZTexture") {
4945 saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
4946 saved_node_pos_dirty = true;
4947 _add_node(curve_xyz_node_option_idx, {}, arr[i], i);
4948 } else if (ClassDB::get_parent_class(type) == "Texture2D") {
4949 saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
4950 saved_node_pos_dirty = true;
4951 _add_node(texture2d_node_option_idx, {}, arr[i], i);
4952 } else if (type == "Texture2DArray") {
4953 saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
4954 saved_node_pos_dirty = true;
4955 _add_node(texture2d_array_node_option_idx, {}, arr[i], i);
4956 } else if (ClassDB::get_parent_class(type) == "Texture3D") {
4957 saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
4958 saved_node_pos_dirty = true;
4959 _add_node(texture3d_node_option_idx, {}, arr[i], i);
4960 } else if (type == "Cubemap") {
4961 saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
4962 saved_node_pos_dirty = true;
4963 _add_node(cubemap_node_option_idx, {}, arr[i], i);
4964 }
4965 }
4966 }
4967 undo_redo->commit_action();
4968 }
4969 }
4970}
4971
4972void VisualShaderEditor::_show_preview_text() {
4973 preview_showed = !preview_showed;
4974 if (preview_showed) {
4975 if (preview_first) {
4976 preview_window->set_size(Size2(400 * EDSCALE, 600 * EDSCALE));
4977 preview_window->popup_centered();
4978 preview_first = false;
4979 } else {
4980 preview_window->popup();
4981 }
4982 _preview_size_changed();
4983
4984 if (pending_update_preview) {
4985 _update_preview();
4986 pending_update_preview = false;
4987 }
4988 } else {
4989 preview_window->hide();
4990 }
4991}
4992
4993void VisualShaderEditor::_preview_close_requested() {
4994 preview_showed = false;
4995 preview_window->hide();
4996 preview_shader->set_pressed(false);
4997}
4998
4999void VisualShaderEditor::_preview_size_changed() {
5000 preview_vbox->set_custom_minimum_size(preview_window->get_size());
5001}
5002
5003static ShaderLanguage::DataType _visual_shader_editor_get_global_shader_uniform_type(const StringName &p_variable) {
5004 RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(p_variable);
5005 return (ShaderLanguage::DataType)RS::global_shader_uniform_type_get_shader_datatype(gvt);
5006}
5007
5008void VisualShaderEditor::_update_preview() {
5009 if (!preview_showed) {
5010 pending_update_preview = true;
5011 return;
5012 }
5013
5014 String code = visual_shader->get_code();
5015
5016 preview_text->set_text(code);
5017
5018 ShaderLanguage::ShaderCompileInfo info;
5019 info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode()));
5020 info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode()));
5021 info.shader_types = ShaderTypes::get_singleton()->get_types();
5022 info.global_shader_uniform_type_func = _visual_shader_editor_get_global_shader_uniform_type;
5023
5024 ShaderLanguage sl;
5025
5026 Error err = sl.compile(code, info);
5027
5028 for (int i = 0; i < preview_text->get_line_count(); i++) {
5029 preview_text->set_line_background_color(i, Color(0, 0, 0, 0));
5030 }
5031 if (err != OK) {
5032 Color error_line_color = EDITOR_GET("text_editor/theme/highlighting/mark_color");
5033 preview_text->set_line_background_color(sl.get_error_line() - 1, error_line_color);
5034 error_panel->show();
5035
5036 String text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text();
5037 error_label->set_text(text);
5038 shader_error = true;
5039 } else {
5040 error_panel->hide();
5041 shader_error = false;
5042 }
5043}
5044
5045void VisualShaderEditor::_update_next_previews(int p_node_id) {
5046 VisualShader::Type type = get_current_shader_type();
5047
5048 LocalVector<int> nodes;
5049 _get_next_nodes_recursively(type, p_node_id, nodes);
5050
5051 for (int node_id : nodes) {
5052 if (graph_plugin->is_preview_visible(node_id)) {
5053 graph_plugin->update_node_deferred(type, node_id);
5054 }
5055 }
5056}
5057
5058void VisualShaderEditor::_get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const {
5059 const LocalVector<int> &next_connections = visual_shader->get_next_connected_nodes(p_type, p_node_id);
5060
5061 for (int node_id : next_connections) {
5062 r_nodes.push_back(node_id);
5063 _get_next_nodes_recursively(p_type, node_id, r_nodes);
5064 }
5065}
5066
5067void VisualShaderEditor::_visibility_changed() {
5068 if (!is_visible()) {
5069 if (preview_window->is_visible()) {
5070 preview_shader->set_pressed(false);
5071 preview_window->hide();
5072 preview_showed = false;
5073 }
5074 }
5075}
5076
5077void VisualShaderEditor::_bind_methods() {
5078 ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes);
5079 ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
5080 ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node);
5081 ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed);
5082 ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
5083 ClassDB::bind_method("_parameter_ref_select_item", &VisualShaderEditor::_parameter_ref_select_item);
5084 ClassDB::bind_method("_varying_select_item", &VisualShaderEditor::_varying_select_item);
5085 ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
5086 ClassDB::bind_method("_clear_copy_buffer", &VisualShaderEditor::_clear_copy_buffer);
5087 ClassDB::bind_method("_update_parameters", &VisualShaderEditor::_update_parameters);
5088 ClassDB::bind_method("_update_varyings", &VisualShaderEditor::_update_varyings);
5089 ClassDB::bind_method("_update_varying_tree", &VisualShaderEditor::_update_varying_tree);
5090 ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);
5091 ClassDB::bind_method("_nodes_dragged", &VisualShaderEditor::_nodes_dragged);
5092 ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected);
5093 ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);
5094 ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter);
5095 ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);
5096 ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred);
5097 ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred);
5098 ClassDB::bind_method("_resources_removed", &VisualShaderEditor::_resources_removed);
5099 ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews);
5100
5101 ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
5102}
5103
5104VisualShaderEditor::VisualShaderEditor() {
5105 ShaderLanguage::get_keyword_list(&keyword_list);
5106 EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::_resource_saved));
5107 FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created));
5108 FileSystemDock::get_singleton()->connect("resource_removed", callable_mp(this, &VisualShaderEditor::_resource_removed));
5109
5110 graph = memnew(GraphEdit);
5111 graph->get_menu_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
5112 graph->set_v_size_flags(SIZE_EXPAND_FILL);
5113 graph->set_h_size_flags(SIZE_EXPAND_FILL);
5114 graph->set_show_zoom_label(true);
5115 add_child(graph);
5116 SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor);
5117 float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
5118 graph->set_minimap_opacity(graph_minimap_opacity);
5119 float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
5120 graph->set_connection_lines_curvature(graph_lines_curvature);
5121 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
5122 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT);
5123 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5124 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN);
5125 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_2D);
5126 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_3D);
5127 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR_4D);
5128 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_TRANSFORM);
5129 graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SAMPLER);
5130 //graph->add_valid_left_disconnect_type(0);
5131 graph->set_v_size_flags(SIZE_EXPAND_FILL);
5132 graph->connect("connection_request", callable_mp(this, &VisualShaderEditor::_connection_request), CONNECT_DEFERRED);
5133 graph->connect("disconnection_request", callable_mp(this, &VisualShaderEditor::_disconnection_request), CONNECT_DEFERRED);
5134 graph->connect("node_selected", callable_mp(this, &VisualShaderEditor::_node_selected));
5135 graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_changed));
5136 graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes));
5137 graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(false));
5138 graph->connect("paste_nodes_request", callable_mp(this, &VisualShaderEditor::_paste_nodes).bind(false, Point2()));
5139 graph->connect("close_nodes_request", callable_mp(this, &VisualShaderEditor::_close_nodes_request));
5140 graph->connect("gui_input", callable_mp(this, &VisualShaderEditor::_graph_gui_input));
5141 graph->connect("connection_to_empty", callable_mp(this, &VisualShaderEditor::_connection_to_empty));
5142 graph->connect("connection_from_empty", callable_mp(this, &VisualShaderEditor::_connection_from_empty));
5143 graph->connect("visibility_changed", callable_mp(this, &VisualShaderEditor::_visibility_changed));
5144 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
5145 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT);
5146 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5147 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_2D);
5148 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_3D);
5149 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR_4D);
5150 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN);
5151
5152 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR);
5153 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT);
5154 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5155 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_2D);
5156 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_3D);
5157 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR_4D);
5158 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_BOOLEAN);
5159
5160 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR);
5161 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR_INT);
5162 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5163 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_2D);
5164 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_3D);
5165 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_VECTOR_4D);
5166 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_UINT, VisualShaderNode::PORT_TYPE_BOOLEAN);
5167
5168 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR);
5169 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR_INT);
5170 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5171 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_2D);
5172 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_3D);
5173 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_VECTOR_4D);
5174 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_2D, VisualShaderNode::PORT_TYPE_BOOLEAN);
5175
5176 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR);
5177 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR_INT);
5178 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5179 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_2D);
5180 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_3D);
5181 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_VECTOR_4D);
5182 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_3D, VisualShaderNode::PORT_TYPE_BOOLEAN);
5183
5184 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR);
5185 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR_INT);
5186 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5187 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_2D);
5188 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_3D);
5189 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_VECTOR_4D);
5190 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR_4D, VisualShaderNode::PORT_TYPE_BOOLEAN);
5191
5192 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR);
5193 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_INT);
5194 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_UINT);
5195 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_2D);
5196 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_3D);
5197 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR_4D);
5198 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN);
5199
5200 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);
5201 graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER);
5202
5203 VSeparator *vs = memnew(VSeparator);
5204 graph->get_menu_hbox()->add_child(vs);
5205 graph->get_menu_hbox()->move_child(vs, 0);
5206
5207 custom_mode_box = memnew(CheckBox);
5208 custom_mode_box->set_text(TTR("Custom"));
5209 custom_mode_box->set_pressed(false);
5210 custom_mode_box->set_visible(false);
5211 custom_mode_box->connect("toggled", callable_mp(this, &VisualShaderEditor::_custom_mode_toggled));
5212
5213 edit_type_standard = memnew(OptionButton);
5214 edit_type_standard->add_item(TTR("Vertex"));
5215 edit_type_standard->add_item(TTR("Fragment"));
5216 edit_type_standard->add_item(TTR("Light"));
5217 edit_type_standard->select(1);
5218 edit_type_standard->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
5219
5220 edit_type_particles = memnew(OptionButton);
5221 edit_type_particles->add_item(TTR("Start"));
5222 edit_type_particles->add_item(TTR("Process"));
5223 edit_type_particles->add_item(TTR("Collide"));
5224 edit_type_particles->select(0);
5225 edit_type_particles->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
5226
5227 edit_type_sky = memnew(OptionButton);
5228 edit_type_sky->add_item(TTR("Sky"));
5229 edit_type_sky->select(0);
5230 edit_type_sky->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
5231
5232 edit_type_fog = memnew(OptionButton);
5233 edit_type_fog->add_item(TTR("Fog"));
5234 edit_type_fog->select(0);
5235 edit_type_fog->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
5236
5237 edit_type = edit_type_standard;
5238
5239 graph->get_menu_hbox()->add_child(custom_mode_box);
5240 graph->get_menu_hbox()->move_child(custom_mode_box, 0);
5241 graph->get_menu_hbox()->add_child(edit_type_standard);
5242 graph->get_menu_hbox()->move_child(edit_type_standard, 0);
5243 graph->get_menu_hbox()->add_child(edit_type_particles);
5244 graph->get_menu_hbox()->move_child(edit_type_particles, 0);
5245 graph->get_menu_hbox()->add_child(edit_type_sky);
5246 graph->get_menu_hbox()->move_child(edit_type_sky, 0);
5247 graph->get_menu_hbox()->add_child(edit_type_fog);
5248 graph->get_menu_hbox()->move_child(edit_type_fog, 0);
5249
5250 add_node = memnew(Button);
5251 add_node->set_flat(true);
5252 add_node->set_text(TTR("Add Node..."));
5253 graph->get_menu_hbox()->add_child(add_node);
5254 graph->get_menu_hbox()->move_child(add_node, 0);
5255 add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog).bind(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX));
5256
5257 varying_button = memnew(MenuButton);
5258 varying_button->set_text(TTR("Manage Varyings"));
5259 varying_button->set_switch_on_hover(true);
5260 graph->get_menu_hbox()->add_child(varying_button);
5261
5262 PopupMenu *varying_menu = varying_button->get_popup();
5263 varying_menu->add_item(TTR("Add Varying"), int(VaryingMenuOptions::ADD));
5264 varying_menu->add_item(TTR("Remove Varying"), int(VaryingMenuOptions::REMOVE));
5265 varying_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_varying_menu_id_pressed));
5266
5267 preview_shader = memnew(Button);
5268 preview_shader->set_flat(true);
5269 preview_shader->set_toggle_mode(true);
5270 preview_shader->set_tooltip_text(TTR("Show generated shader code."));
5271 graph->get_menu_hbox()->add_child(preview_shader);
5272 preview_shader->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_preview_text));
5273
5274 ///////////////////////////////////////
5275 // PREVIEW WINDOW
5276 ///////////////////////////////////////
5277
5278 preview_window = memnew(Window);
5279 preview_window->set_title(TTR("Generated Shader Code"));
5280 preview_window->set_visible(preview_showed);
5281 preview_window->connect("close_requested", callable_mp(this, &VisualShaderEditor::_preview_close_requested));
5282 preview_window->connect("size_changed", callable_mp(this, &VisualShaderEditor::_preview_size_changed));
5283 add_child(preview_window);
5284
5285 preview_vbox = memnew(VBoxContainer);
5286 preview_window->add_child(preview_vbox);
5287 preview_vbox->add_theme_constant_override("separation", 0);
5288
5289 preview_text = memnew(CodeEdit);
5290 syntax_highlighter.instantiate();
5291 preview_vbox->add_child(preview_text);
5292 preview_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
5293 preview_text->set_syntax_highlighter(syntax_highlighter);
5294 preview_text->set_draw_line_numbers(true);
5295 preview_text->set_editable(false);
5296
5297 error_panel = memnew(PanelContainer);
5298 preview_vbox->add_child(error_panel);
5299 error_panel->set_visible(false);
5300
5301 error_label = memnew(Label);
5302 error_panel->add_child(error_label);
5303 error_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
5304
5305 ///////////////////////////////////////
5306 // POPUP MENU
5307 ///////////////////////////////////////
5308
5309 popup_menu = memnew(PopupMenu);
5310 add_child(popup_menu);
5311 popup_menu->add_item(TTR("Add Node"), NodeMenuOptions::ADD);
5312 popup_menu->add_separator();
5313 popup_menu->add_item(TTR("Cut"), NodeMenuOptions::CUT);
5314 popup_menu->add_item(TTR("Copy"), NodeMenuOptions::COPY);
5315 popup_menu->add_item(TTR("Paste"), NodeMenuOptions::PASTE);
5316 popup_menu->add_item(TTR("Delete"), NodeMenuOptions::DELETE);
5317 popup_menu->add_item(TTR("Duplicate"), NodeMenuOptions::DUPLICATE);
5318 popup_menu->add_item(TTR("Clear Copy Buffer"), NodeMenuOptions::CLEAR_COPY_BUFFER);
5319 popup_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed));
5320
5321 ///////////////////////////////////////
5322 // SHADER NODES TREE
5323 ///////////////////////////////////////
5324
5325 VBoxContainer *members_vb = memnew(VBoxContainer);
5326 members_vb->set_v_size_flags(SIZE_EXPAND_FILL);
5327
5328 HBoxContainer *filter_hb = memnew(HBoxContainer);
5329 members_vb->add_child(filter_hb);
5330
5331 node_filter = memnew(LineEdit);
5332 filter_hb->add_child(node_filter);
5333 node_filter->connect("text_changed", callable_mp(this, &VisualShaderEditor::_member_filter_changed));
5334 node_filter->connect("gui_input", callable_mp(this, &VisualShaderEditor::_sbox_input));
5335 node_filter->set_h_size_flags(SIZE_EXPAND_FILL);
5336 node_filter->set_placeholder(TTR("Search"));
5337
5338 tools = memnew(MenuButton);
5339 filter_hb->add_child(tools);
5340 tools->set_tooltip_text(TTR("Options"));
5341 tools->get_popup()->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_tools_menu_option));
5342 tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL);
5343 tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL);
5344
5345 members = memnew(Tree);
5346 members_vb->add_child(members);
5347 SET_DRAG_FORWARDING_GCD(members, VisualShaderEditor);
5348 members->set_h_size_flags(SIZE_EXPAND_FILL);
5349 members->set_v_size_flags(SIZE_EXPAND_FILL);
5350 members->set_hide_root(true);
5351 members->set_allow_reselect(true);
5352 members->set_hide_folding(false);
5353 members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));
5354 members->connect("item_activated", callable_mp(this, &VisualShaderEditor::_member_create));
5355 members->connect("item_selected", callable_mp(this, &VisualShaderEditor::_member_selected));
5356 members->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_member_unselected));
5357
5358 HBoxContainer *desc_hbox = memnew(HBoxContainer);
5359 members_vb->add_child(desc_hbox);
5360
5361 Label *desc_label = memnew(Label);
5362 desc_hbox->add_child(desc_label);
5363 desc_label->set_text(TTR("Description:"));
5364
5365 desc_hbox->add_spacer();
5366
5367 highend_label = memnew(Label);
5368 desc_hbox->add_child(highend_label);
5369 highend_label->set_visible(false);
5370 highend_label->set_text("Vulkan");
5371 highend_label->set_mouse_filter(Control::MOUSE_FILTER_STOP);
5372 highend_label->set_tooltip_text(TTR("High-end node"));
5373
5374 node_desc = memnew(RichTextLabel);
5375 members_vb->add_child(node_desc);
5376 node_desc->set_h_size_flags(SIZE_EXPAND_FILL);
5377 node_desc->set_v_size_flags(SIZE_FILL);
5378 node_desc->set_custom_minimum_size(Size2(0, 70 * EDSCALE));
5379
5380 members_dialog = memnew(ConfirmationDialog);
5381 members_dialog->set_title(TTR("Create Shader Node"));
5382 members_dialog->set_exclusive(false);
5383 members_dialog->add_child(members_vb);
5384 members_dialog->set_ok_button_text(TTR("Create"));
5385 members_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create));
5386 members_dialog->get_ok_button()->set_disabled(true);
5387 members_dialog->connect("canceled", callable_mp(this, &VisualShaderEditor::_member_cancel));
5388 add_child(members_dialog);
5389
5390 // add varyings dialog
5391 {
5392 add_varying_dialog = memnew(ConfirmationDialog);
5393 add_varying_dialog->set_title(TTR("Create Shader Varying"));
5394 add_varying_dialog->set_exclusive(false);
5395 add_varying_dialog->set_ok_button_text(TTR("Create"));
5396 add_varying_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_varying_create));
5397 add_varying_dialog->get_ok_button()->set_disabled(true);
5398 add_child(add_varying_dialog);
5399
5400 VBoxContainer *vb = memnew(VBoxContainer);
5401 add_varying_dialog->add_child(vb);
5402
5403 HBoxContainer *hb = memnew(HBoxContainer);
5404 vb->add_child(hb);
5405 hb->set_h_size_flags(SIZE_EXPAND_FILL);
5406
5407 varying_type = memnew(OptionButton);
5408 hb->add_child(varying_type);
5409 varying_type->add_item("Float");
5410 varying_type->add_item("Int");
5411 varying_type->add_item("UInt");
5412 varying_type->add_item("Vector2");
5413 varying_type->add_item("Vector3");
5414 varying_type->add_item("Vector4");
5415 varying_type->add_item("Boolean");
5416 varying_type->add_item("Transform");
5417
5418 varying_name = memnew(LineEdit);
5419 hb->add_child(varying_name);
5420 varying_name->set_custom_minimum_size(Size2(150 * EDSCALE, 0));
5421 varying_name->set_h_size_flags(SIZE_EXPAND_FILL);
5422 varying_name->connect("text_changed", callable_mp(this, &VisualShaderEditor::_varying_name_changed));
5423
5424 varying_mode = memnew(OptionButton);
5425 hb->add_child(varying_mode);
5426 varying_mode->add_item("Vertex -> [Fragment, Light]");
5427 varying_mode->add_item("Fragment -> Light");
5428
5429 varying_error_label = memnew(Label);
5430 vb->add_child(varying_error_label);
5431 varying_error_label->set_h_size_flags(SIZE_EXPAND_FILL);
5432
5433 varying_error_label->hide();
5434 }
5435
5436 // remove varying dialog
5437 {
5438 remove_varying_dialog = memnew(ConfirmationDialog);
5439 remove_varying_dialog->set_title(TTR("Delete Shader Varying"));
5440 remove_varying_dialog->set_exclusive(false);
5441 remove_varying_dialog->set_ok_button_text(TTR("Delete"));
5442 remove_varying_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_varying_deleted));
5443 add_child(remove_varying_dialog);
5444
5445 VBoxContainer *vb = memnew(VBoxContainer);
5446 remove_varying_dialog->add_child(vb);
5447
5448 varyings = memnew(Tree);
5449 vb->add_child(varyings);
5450 varyings->set_h_size_flags(SIZE_EXPAND_FILL);
5451 varyings->set_v_size_flags(SIZE_EXPAND_FILL);
5452 varyings->set_hide_root(true);
5453 varyings->set_allow_reselect(true);
5454 varyings->set_hide_folding(false);
5455 varyings->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE));
5456 varyings->connect("item_activated", callable_mp(this, &VisualShaderEditor::_varying_deleted));
5457 varyings->connect("item_selected", callable_mp(this, &VisualShaderEditor::_varying_selected));
5458 varyings->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_varying_unselected));
5459 }
5460
5461 alert = memnew(AcceptDialog);
5462 alert->get_label()->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
5463 alert->get_label()->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
5464 alert->get_label()->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
5465 alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);
5466 add_child(alert);
5467
5468 comment_title_change_popup = memnew(PopupPanel);
5469 comment_title_change_edit = memnew(LineEdit);
5470 comment_title_change_edit->set_expand_to_text_length_enabled(true);
5471 comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed));
5472 comment_title_change_edit->connect("text_submitted", callable_mp(this, &VisualShaderEditor::_comment_title_text_submitted));
5473 comment_title_change_popup->add_child(comment_title_change_edit);
5474 comment_title_change_edit->reset_size();
5475 comment_title_change_popup->reset_size();
5476 comment_title_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_title_popup_focus_out));
5477 comment_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_title_popup_hide));
5478 add_child(comment_title_change_popup);
5479
5480 comment_desc_change_popup = memnew(PopupPanel);
5481 VBoxContainer *comment_desc_vbox = memnew(VBoxContainer);
5482 comment_desc_change_popup->add_child(comment_desc_vbox);
5483 comment_desc_change_edit = memnew(TextEdit);
5484 comment_desc_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_desc_text_changed));
5485 comment_desc_vbox->add_child(comment_desc_change_edit);
5486 comment_desc_change_edit->set_custom_minimum_size(Size2(300 * EDSCALE, 150 * EDSCALE));
5487 comment_desc_change_edit->reset_size();
5488 comment_desc_change_popup->reset_size();
5489 comment_desc_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
5490 comment_desc_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_desc_popup_hide));
5491 Button *comment_desc_confirm_button = memnew(Button);
5492 comment_desc_confirm_button->set_text(TTR("OK"));
5493 comment_desc_vbox->add_child(comment_desc_confirm_button);
5494 comment_desc_confirm_button->connect("pressed", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
5495 add_child(comment_desc_change_popup);
5496
5497 ///////////////////////////////////////
5498 // SHADER NODES TREE OPTIONS
5499 ///////////////////////////////////////
5500
5501 // COLOR
5502
5503 add_options.push_back(AddOption("ColorFunc", "Color/Common", "VisualShaderNodeColorFunc", TTR("Color function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5504 add_options.push_back(AddOption("ColorOp", "Color/Common", "VisualShaderNodeColorOp", TTR("Color operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5505
5506 add_options.push_back(AddOption("Grayscale", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5507 add_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));
5508 add_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));
5509 add_options.push_back(AddOption("Sepia", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), { VisualShaderNodeColorFunc::FUNC_SEPIA }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5510
5511 add_options.push_back(AddOption("Burn", "Color/Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), { VisualShaderNodeColorOp::OP_BURN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5512 add_options.push_back(AddOption("Darken", "Color/Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), { VisualShaderNodeColorOp::OP_DARKEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5513 add_options.push_back(AddOption("Difference", "Color/Operators", "VisualShaderNodeColorOp", TTR("Difference operator."), { VisualShaderNodeColorOp::OP_DIFFERENCE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5514 add_options.push_back(AddOption("Dodge", "Color/Operators", "VisualShaderNodeColorOp", TTR("Dodge operator."), { VisualShaderNodeColorOp::OP_DODGE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5515 add_options.push_back(AddOption("HardLight", "Color/Operators", "VisualShaderNodeColorOp", TTR("HardLight operator."), { VisualShaderNodeColorOp::OP_HARD_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5516 add_options.push_back(AddOption("Lighten", "Color/Operators", "VisualShaderNodeColorOp", TTR("Lighten operator."), { VisualShaderNodeColorOp::OP_LIGHTEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5517 add_options.push_back(AddOption("Overlay", "Color/Operators", "VisualShaderNodeColorOp", TTR("Overlay operator."), { VisualShaderNodeColorOp::OP_OVERLAY }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5518 add_options.push_back(AddOption("Screen", "Color/Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), { VisualShaderNodeColorOp::OP_SCREEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5519 add_options.push_back(AddOption("SoftLight", "Color/Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), { VisualShaderNodeColorOp::OP_SOFT_LIGHT }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5520
5521 add_options.push_back(AddOption("ColorConstant", "Color/Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
5522 add_options.push_back(AddOption("ColorParameter", "Color/Variables", "VisualShaderNodeColorParameter", TTR("Color parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
5523
5524 // COMMON
5525
5526 add_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));
5527
5528 // CONDITIONAL
5529
5530 const String &compare_func_desc = TTR("Returns the boolean result of the %s comparison between two parameters.");
5531
5532 add_options.push_back(AddOption("Equal (==)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Equal (==)")), { VisualShaderNodeCompare::FUNC_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
5533 add_options.push_back(AddOption("GreaterThan (>)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than (>)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
5534 add_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));
5535 add_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));
5536 add_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));
5537 add_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));
5538 add_options.push_back(AddOption("LessThan (<)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), { VisualShaderNodeCompare::FUNC_LESS_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
5539 add_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));
5540 add_options.push_back(AddOption("NotEqual (!=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), { VisualShaderNodeCompare::FUNC_NOT_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
5541 add_options.push_back(AddOption("Switch (==)", "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));
5542 add_options.push_back(AddOption("Switch2D (==)", "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));
5543 add_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));
5544 add_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));
5545 add_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));
5546 add_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));
5547 add_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));
5548
5549 add_options.push_back(AddOption("Compare (==)", "Conditional/Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
5550 add_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));
5551
5552 add_options.push_back(AddOption("BooleanConstant", "Conditional/Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
5553 add_options.push_back(AddOption("BooleanParameter", "Conditional/Variables", "VisualShaderNodeBooleanParameter", TTR("Boolean parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
5554
5555 // INPUT
5556
5557 const String translation_gdsl = "\n\n" + TTR("Translated to '%s' in Godot Shading Language.");
5558 const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.") + translation_gdsl;
5559
5560 // NODE3D-FOR-ALL
5561
5562 add_options.push_back(AddOption("Exposure", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "exposure", "EXPOSURE"), { "exposure" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));
5563 add_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));
5564 add_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));
5565 add_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));
5566 add_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));
5567 add_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));
5568 add_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));
5569 add_options.push_back(AddOption("Time", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));
5570 add_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));
5571 add_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));
5572 add_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));
5573 add_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));
5574
5575 // CANVASITEM-FOR-ALL
5576
5577 add_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));
5578 add_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));
5579 add_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));
5580 add_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));
5581
5582 // PARTICLES-FOR-ALL
5583
5584 add_options.push_back(AddOption("Active", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active", "ACTIVE"), { "active" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
5585 add_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));
5586 add_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));
5587 add_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));
5588 add_options.push_back(AddOption("Delta", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta", "DELTA"), { "delta" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
5589 add_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));
5590 add_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));
5591 add_options.push_back(AddOption("LifeTime", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime", "LIFETIME"), { "lifetime" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
5592 add_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));
5593 add_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));
5594 add_options.push_back(AddOption("Restart", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart", "RESTART"), { "restart" }, VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES));
5595 add_options.push_back(AddOption("Time", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES));
5596 add_options.push_back(AddOption("Transform", "Input/All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform", "TRANSFORM"), { "transform" }, VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES));
5597 add_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));
5598
5599 /////////////////
5600
5601 add_options.push_back(AddOption("Input", "Input/Common", "VisualShaderNodeInput", TTR("Input parameter.")));
5602
5603 const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;
5604 const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.") + translation_gdsl;
5605 const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.") + translation_gdsl;
5606 const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.") + translation_gdsl;
5607 const String input_param_for_fog_shader_mode = TTR("'%s' input parameter for fog shader mode.") + translation_gdsl;
5608 const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.") + translation_gdsl;
5609 const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.") + translation_gdsl;
5610 const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.") + translation_gdsl;
5611 const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode.") + translation_gdsl;
5612 const String input_param_for_collide_shader_mode = TTR("'%s' input parameter for collide shader mode." + translation_gdsl);
5613 const String input_param_for_start_and_process_shader_mode = TTR("'%s' input parameter for start and process shader modes.") + translation_gdsl;
5614 const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes.") + translation_gdsl;
5615 const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes.") + translation_gdsl;
5616
5617 // NODE3D INPUTS
5618
5619 add_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));
5620 add_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));
5621 add_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));
5622 add_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));
5623 add_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));
5624 add_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));
5625 add_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));
5626 add_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));
5627 add_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));
5628 add_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));
5629 add_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));
5630 add_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));
5631 add_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));
5632 add_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));
5633 add_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));
5634 add_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));
5635 add_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));
5636 add_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));
5637 add_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));
5638 add_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));
5639 add_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));
5640 add_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));
5641
5642 add_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));
5643 add_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));
5644 add_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));
5645 add_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));
5646 add_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));
5647 add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
5648 add_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));
5649 add_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));
5650 add_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));
5651 add_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));
5652 add_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));
5653 add_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));
5654 add_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));
5655 add_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));
5656 add_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));
5657 add_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));
5658 add_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));
5659 add_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));
5660
5661 add_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));
5662 add_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));
5663 add_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));
5664 add_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));
5665 add_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));
5666 add_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));
5667 add_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));
5668 add_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));
5669 add_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));
5670 add_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));
5671 add_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));
5672 add_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));
5673
5674 // CANVASITEM INPUTS
5675
5676 add_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));
5677 add_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));
5678 add_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));
5679 add_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));
5680 add_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));
5681 add_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));
5682 add_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));
5683 add_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));
5684 add_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));
5685
5686 add_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));
5687 add_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));
5688 add_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));
5689 add_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));
5690 add_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));
5691 add_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));
5692 add_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));
5693 add_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));
5694 add_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));
5695 add_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));
5696
5697 add_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));
5698 add_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));
5699 add_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));
5700 add_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));
5701 add_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));
5702 add_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));
5703 add_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));
5704 add_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));
5705 add_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));
5706 add_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));
5707 add_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));
5708 add_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));
5709 add_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));
5710 add_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));
5711
5712 // SKY INPUTS
5713
5714 add_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));
5715 add_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));
5716 add_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));
5717 add_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));
5718 add_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));
5719 add_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));
5720 add_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));
5721 add_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));
5722 add_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));
5723 add_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));
5724 add_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));
5725 add_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));
5726 add_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));
5727 add_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));
5728 add_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));
5729 add_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));
5730 add_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));
5731 add_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));
5732 add_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));
5733 add_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));
5734 add_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));
5735 add_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));
5736 add_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));
5737 add_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));
5738 add_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));
5739 add_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));
5740
5741 add_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));
5742 add_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));
5743
5744 // FOG INPUTS
5745
5746 add_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));
5747 add_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));
5748 add_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));
5749 add_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));
5750 add_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));
5751 add_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));
5752
5753 // PARTICLES INPUTS
5754
5755 add_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));
5756 add_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));
5757
5758 // PARTICLES
5759
5760 add_options.push_back(AddOption("EmitParticle", "Particles", "VisualShaderNodeParticleEmit", "", {}, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
5761 add_options.push_back(AddOption("ParticleAccelerator", "Particles", "VisualShaderNodeParticleAccelerator", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
5762 add_options.push_back(AddOption("ParticleRandomness", "Particles", "VisualShaderNodeParticleRandomness", "", {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
5763 add_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));
5764
5765 add_options.push_back(AddOption("BoxEmitter", "Particles/Emitters", "VisualShaderNodeParticleBoxEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
5766 add_options.push_back(AddOption("MeshEmitter", "Particles/Emitters", "VisualShaderNodeParticleMeshEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
5767 add_options.push_back(AddOption("RingEmitter", "Particles/Emitters", "VisualShaderNodeParticleRingEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
5768 add_options.push_back(AddOption("SphereEmitter", "Particles/Emitters", "VisualShaderNodeParticleSphereEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
5769
5770 add_options.push_back(AddOption("ConeVelocity", "Particles/Velocity", "VisualShaderNodeParticleConeVelocity", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
5771
5772 // SCALAR
5773
5774 add_options.push_back(AddOption("FloatFunc", "Scalar/Common", "VisualShaderNodeFloatFunc", TTR("Float function."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5775 add_options.push_back(AddOption("FloatOp", "Scalar/Common", "VisualShaderNodeFloatOp", TTR("Float operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5776 add_options.push_back(AddOption("IntFunc", "Scalar/Common", "VisualShaderNodeIntFunc", TTR("Integer function."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5777 add_options.push_back(AddOption("IntOp", "Scalar/Common", "VisualShaderNodeIntOp", TTR("Integer operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5778 add_options.push_back(AddOption("UIntFunc", "Scalar/Common", "VisualShaderNodeUIntFunc", TTR("Unsigned integer function."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5779 add_options.push_back(AddOption("UIntOp", "Scalar/Common", "VisualShaderNodeUIntOp", TTR("Unsigned integer operator."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5780
5781 // CONSTANTS
5782
5783 for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {
5784 add_options.push_back(AddOption(float_constant_defs[i].name, "Scalar/Constants", "VisualShaderNodeFloatConstant", float_constant_defs[i].desc, { float_constant_defs[i].value }, VisualShaderNode::PORT_TYPE_SCALAR));
5785 }
5786 // FUNCTIONS
5787
5788 add_options.push_back(AddOption("Abs", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR));
5789 add_options.push_back(AddOption("Abs", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Returns the absolute value of the parameter."), { VisualShaderNodeIntFunc::FUNC_ABS }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5790 add_options.push_back(AddOption("ACos", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOS }, VisualShaderNode::PORT_TYPE_SCALAR));
5791 add_options.push_back(AddOption("ACosH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ACOSH }, VisualShaderNode::PORT_TYPE_SCALAR));
5792 add_options.push_back(AddOption("ASin", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASIN }, VisualShaderNode::PORT_TYPE_SCALAR));
5793 add_options.push_back(AddOption("ASinH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ASINH }, VisualShaderNode::PORT_TYPE_SCALAR));
5794 add_options.push_back(AddOption("ATan", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATAN }, VisualShaderNode::PORT_TYPE_SCALAR));
5795 add_options.push_back(AddOption("ATan2", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the arc-tangent of the parameters."), { VisualShaderNodeFloatOp::OP_ATAN2 }, VisualShaderNode::PORT_TYPE_SCALAR));
5796 add_options.push_back(AddOption("ATanH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_ATANH }, VisualShaderNode::PORT_TYPE_SCALAR));
5797 add_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));
5798 add_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));
5799 add_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));
5800 add_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));
5801 add_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));
5802 add_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));
5803 add_options.push_back(AddOption("Cos", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COS }, VisualShaderNode::PORT_TYPE_SCALAR));
5804 add_options.push_back(AddOption("CosH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic cosine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_COSH }, VisualShaderNode::PORT_TYPE_SCALAR));
5805 add_options.push_back(AddOption("Degrees", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in radians to degrees."), { VisualShaderNodeFloatFunc::FUNC_DEGREES }, VisualShaderNode::PORT_TYPE_SCALAR));
5806 add_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));
5807 add_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));
5808 add_options.push_back(AddOption("Exp", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-e Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP }, VisualShaderNode::PORT_TYPE_SCALAR));
5809 add_options.push_back(AddOption("Exp2", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 Exponential."), { VisualShaderNodeFloatFunc::FUNC_EXP2 }, VisualShaderNode::PORT_TYPE_SCALAR));
5810 add_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));
5811 add_options.push_back(AddOption("Fract", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), { VisualShaderNodeFloatFunc::FUNC_FRACT }, VisualShaderNode::PORT_TYPE_SCALAR));
5812 add_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));
5813 add_options.push_back(AddOption("Log", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Natural logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG }, VisualShaderNode::PORT_TYPE_SCALAR));
5814 add_options.push_back(AddOption("Log2", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), { VisualShaderNodeFloatFunc::FUNC_LOG2 }, VisualShaderNode::PORT_TYPE_SCALAR));
5815 add_options.push_back(AddOption("Max", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), { VisualShaderNodeFloatOp::OP_MAX }, VisualShaderNode::PORT_TYPE_SCALAR));
5816 add_options.push_back(AddOption("Min", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), { VisualShaderNodeFloatOp::OP_MIN }, VisualShaderNode::PORT_TYPE_SCALAR));
5817 add_options.push_back(AddOption("Mix", "Scalar/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two scalars."), { VisualShaderNodeMix::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
5818 add_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));
5819 add_options.push_back(AddOption("Negate (*-1)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR));
5820 add_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));
5821 add_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));
5822 add_options.push_back(AddOption("OneMinus (1-)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), { VisualShaderNodeFloatFunc::FUNC_ONEMINUS }, VisualShaderNode::PORT_TYPE_SCALAR));
5823 add_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));
5824 add_options.push_back(AddOption("Radians", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeFloatFunc::FUNC_RADIANS }, VisualShaderNode::PORT_TYPE_SCALAR));
5825 add_options.push_back(AddOption("Reciprocal", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), { VisualShaderNodeFloatFunc::FUNC_RECIPROCAL }, VisualShaderNode::PORT_TYPE_SCALAR));
5826 add_options.push_back(AddOption("Round", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUND }, VisualShaderNode::PORT_TYPE_SCALAR));
5827 add_options.push_back(AddOption("RoundEven", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUNDEVEN }, VisualShaderNode::PORT_TYPE_SCALAR));
5828 add_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));
5829 add_options.push_back(AddOption("Sign", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR));
5830 add_options.push_back(AddOption("Sign", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Extracts the sign of the parameter."), { VisualShaderNodeIntFunc::FUNC_SIGN }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5831 add_options.push_back(AddOption("Sin", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SIN }, VisualShaderNode::PORT_TYPE_SCALAR));
5832 add_options.push_back(AddOption("SinH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic sine of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SINH }, VisualShaderNode::PORT_TYPE_SCALAR));
5833 add_options.push_back(AddOption("Sqrt", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the square root of the parameter."), { VisualShaderNodeFloatFunc::FUNC_SQRT }, VisualShaderNode::PORT_TYPE_SCALAR));
5834 add_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));
5835 add_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));
5836 add_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));
5837 add_options.push_back(AddOption("Tan", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TAN }, VisualShaderNode::PORT_TYPE_SCALAR));
5838 add_options.push_back(AddOption("TanH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TANH }, VisualShaderNode::PORT_TYPE_SCALAR));
5839 add_options.push_back(AddOption("Trunc", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TRUNC }, VisualShaderNode::PORT_TYPE_SCALAR));
5840
5841 add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), { VisualShaderNodeFloatOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR));
5842 add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), { VisualShaderNodeIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5843 add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Sums two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5844 add_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));
5845 add_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));
5846 add_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));
5847 add_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));
5848 add_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));
5849 add_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));
5850 add_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));
5851 add_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));
5852 add_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));
5853 add_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));
5854 add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), { VisualShaderNodeFloatOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR));
5855 add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), { VisualShaderNodeIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5856 add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Divides two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5857 add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR));
5858 add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), { VisualShaderNodeIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5859 add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Multiplies two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5860 add_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));
5861 add_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));
5862 add_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));
5863 add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), { VisualShaderNodeFloatOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR));
5864 add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), { VisualShaderNodeIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5865 add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeUIntOp", TTR("Subtracts two unsigned integer scalars."), { VisualShaderNodeUIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5866
5867 add_options.push_back(AddOption("FloatConstant", "Scalar/Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5868 add_options.push_back(AddOption("IntConstant", "Scalar/Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5869 add_options.push_back(AddOption("UIntConstant", "Scalar/Variables", "VisualShaderNodeUIntConstant", TTR("Scalar unsigned integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5870 add_options.push_back(AddOption("FloatParameter", "Scalar/Variables", "VisualShaderNodeFloatParameter", TTR("Scalar floating-point parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5871 add_options.push_back(AddOption("IntParameter", "Scalar/Variables", "VisualShaderNodeIntParameter", TTR("Scalar integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
5872 add_options.push_back(AddOption("UIntParameter", "Scalar/Variables", "VisualShaderNodeUIntParameter", TTR("Scalar unsigned integer parameter."), {}, VisualShaderNode::PORT_TYPE_SCALAR_UINT));
5873
5874 // SDF
5875 {
5876 add_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));
5877 add_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));
5878 add_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));
5879 add_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));
5880 add_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));
5881 }
5882
5883 // TEXTURES
5884
5885 add_options.push_back(AddOption("UVFunc", "Textures/Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
5886 add_options.push_back(AddOption("UVPolarCoord", "Textures/Common", "VisualShaderNodeUVPolarCoord", TTR("Polar coordinates conversion applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
5887
5888 cubemap_node_option_idx = add_options.size();
5889 add_options.push_back(AddOption("CubeMap", "Textures/Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
5890 curve_node_option_idx = add_options.size();
5891 add_options.push_back(AddOption("CurveTexture", "Textures/Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5892 curve_xyz_node_option_idx = add_options.size();
5893 add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5894 add_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));
5895 texture2d_node_option_idx = add_options.size();
5896 add_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));
5897 texture2d_node_option_idx = add_options.size();
5898 add_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));
5899 texture2d_node_option_idx = add_options.size();
5900 add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
5901 texture2d_array_node_option_idx = add_options.size();
5902 add_options.push_back(AddOption("Texture2DArray", "Textures/Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
5903 texture3d_node_option_idx = add_options.size();
5904 add_options.push_back(AddOption("Texture3D", "Textures/Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
5905 add_options.push_back(AddOption("UVPanning", "Textures/Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_PANNING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
5906 add_options.push_back(AddOption("UVScaling", "Textures/Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), { VisualShaderNodeUVFunc::FUNC_SCALING }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
5907
5908 add_options.push_back(AddOption("CubeMapParameter", "Textures/Variables", "VisualShaderNodeCubemapParameter", TTR("Cubic texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
5909 add_options.push_back(AddOption("Texture2DParameter", "Textures/Variables", "VisualShaderNodeTexture2DParameter", TTR("2D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
5910 add_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));
5911 add_options.push_back(AddOption("Texture2DArrayParameter", "Textures/Variables", "VisualShaderNodeTexture2DArrayParameter", TTR("2D array of textures parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
5912 add_options.push_back(AddOption("Texture3DParameter", "Textures/Variables", "VisualShaderNodeTexture3DParameter", TTR("3D texture parameter lookup."), {}, VisualShaderNode::PORT_TYPE_SAMPLER));
5913
5914 // TRANSFORM
5915
5916 add_options.push_back(AddOption("TransformFunc", "Transform/Common", "VisualShaderNodeTransformFunc", TTR("Transform function."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
5917 add_options.push_back(AddOption("TransformOp", "Transform/Common", "VisualShaderNodeTransformOp", TTR("Transform operator."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
5918
5919 add_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));
5920 add_options.push_back(AddOption("TransformCompose", "Transform/Composition", "VisualShaderNodeTransformCompose", TTR("Composes transform from four vectors."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
5921 add_options.push_back(AddOption("TransformDecompose", "Transform/Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));
5922
5923 add_options.push_back(AddOption("Determinant", "Transform/Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5924 add_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));
5925 add_options.push_back(AddOption("Inverse", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), { VisualShaderNodeTransformFunc::FUNC_INVERSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));
5926 add_options.push_back(AddOption("Transpose", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), { VisualShaderNodeTransformFunc::FUNC_TRANSPOSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));
5927
5928 add_options.push_back(AddOption("Add (+)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Sums two transforms."), { VisualShaderNodeTransformOp::OP_ADD }, VisualShaderNode::PORT_TYPE_TRANSFORM));
5929 add_options.push_back(AddOption("Divide (/)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Divides two transforms."), { VisualShaderNodeTransformOp::OP_A_DIV_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
5930 add_options.push_back(AddOption("Multiply (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Multiplies two transforms."), { VisualShaderNodeTransformOp::OP_AxB }, VisualShaderNode::PORT_TYPE_TRANSFORM));
5931 add_options.push_back(AddOption("MultiplyComp (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Performs per-component multiplication of two transforms."), { VisualShaderNodeTransformOp::OP_AxB_COMP }, VisualShaderNode::PORT_TYPE_TRANSFORM));
5932 add_options.push_back(AddOption("Subtract (-)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Subtracts two transforms."), { VisualShaderNodeTransformOp::OP_A_MINUS_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
5933 add_options.push_back(AddOption("TransformVectorMult (*)", "Transform/Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5934
5935 add_options.push_back(AddOption("TransformConstant", "Transform/Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
5936 add_options.push_back(AddOption("TransformParameter", "Transform/Variables", "VisualShaderNodeTransformParameter", TTR("Transform parameter."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
5937
5938 // UTILITY
5939
5940 add_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));
5941 add_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));
5942 add_options.push_back(AddOption("RandomRange", "Utility", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5943 add_options.push_back(AddOption("Remap", "Utility", "VisualShaderNodeRemap", TTR("Remaps a given input from the input range to the output range."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
5944 add_options.push_back(AddOption("RotationByAxis", "Utility", "VisualShaderNodeRotationByAxis", TTR("Rotates an input vector by a given angle."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
5945 add_options.push_back(AddOption("RotationByAxis", "Utility", "VisualShaderNodeRotationByAxis", TTR("Rotates an input vector by a given angle."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
5946
5947 // VECTOR
5948
5949 add_options.push_back(AddOption("VectorFunc", "Vector/Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5950 add_options.push_back(AddOption("VectorOp", "Vector/Common", "VisualShaderNodeVectorOp", TTR("Vector operator."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
5951 add_options.push_back(AddOption("VectorCompose", "Vector/Common", "VisualShaderNodeVectorCompose", TTR("Composes vector from scalars.")));
5952 add_options.push_back(AddOption("VectorDecompose", "Vector/Common", "VisualShaderNodeVectorDecompose", TTR("Decomposes vector to scalars.")));
5953
5954 add_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));
5955 add_options.push_back(AddOption("Vector2Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 2D vector to two scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_2D }));
5956 add_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));
5957 add_options.push_back(AddOption("Vector3Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 3D vector to three scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_3D }));
5958 add_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));
5959 add_options.push_back(AddOption("Vector4Decompose", "Vector/Composition", "VisualShaderNodeVectorDecompose", TTR("Decomposes 4D vector to four scalars."), { VisualShaderNodeVectorDecompose::OP_TYPE_VECTOR_4D }));
5960
5961 add_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));
5962 add_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));
5963 add_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));
5964 add_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));
5965 add_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));
5966 add_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));
5967 add_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));
5968 add_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));
5969 add_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));
5970 add_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));
5971 add_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));
5972 add_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));
5973 add_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));
5974 add_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));
5975 add_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));
5976 add_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));
5977 add_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));
5978 add_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));
5979 add_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));
5980 add_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));
5981 add_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));
5982 add_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));
5983 add_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));
5984 add_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));
5985 add_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));
5986 add_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));
5987 add_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));
5988 add_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));
5989 add_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));
5990 add_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));
5991 add_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));
5992 add_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));
5993 add_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));
5994 add_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));
5995 add_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));
5996 add_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));
5997 add_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));
5998 add_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));
5999 add_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));
6000 add_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));
6001 add_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));
6002 add_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));
6003 add_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));
6004 add_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));
6005 add_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));
6006 add_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));
6007 add_options.push_back(AddOption("Distance2D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));
6008 add_options.push_back(AddOption("Distance3D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));
6009 add_options.push_back(AddOption("Distance4D", "Vector/Functions", "VisualShaderNodeVectorDistance", TTR("Returns the distance between two points."), { VisualShaderNodeVectorDistance::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));
6010 add_options.push_back(AddOption("Dot", "Vector/Functions", "VisualShaderNodeDotProduct", TTR("Calculates the dot product of two vectors."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
6011 add_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));
6012 add_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));
6013 add_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));
6014 add_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));
6015 add_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));
6016 add_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));
6017 add_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));
6018 add_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));
6019 add_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));
6020 add_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));
6021 add_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));
6022 add_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));
6023 add_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));
6024 add_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));
6025 add_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));
6026 add_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));
6027 add_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));
6028 add_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));
6029 add_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));
6030 add_options.push_back(AddOption("Length2D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_SCALAR));
6031 add_options.push_back(AddOption("Length3D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_SCALAR));
6032 add_options.push_back(AddOption("Length4D", "Vector/Functions", "VisualShaderNodeVectorLen", TTR("Calculates the length of a vector."), { VisualShaderNodeVectorLen::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_SCALAR));
6033 add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
6034 add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
6035 add_options.push_back(AddOption("Log", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Natural logarithm."), { VisualShaderNodeVectorFunc::FUNC_LOG, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
6036 add_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));
6037 add_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));
6038 add_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));
6039 add_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));
6040 add_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));
6041 add_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));
6042 add_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));
6043 add_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));
6044 add_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));
6045 add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
6046 add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
6047 add_options.push_back(AddOption("Mix", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), { VisualShaderNodeMix::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
6048 add_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));
6049 add_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));
6050 add_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));
6051 add_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));
6052 add_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));
6053 add_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));
6054 add_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));
6055 add_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));
6056 add_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));
6057 add_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));
6058 add_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));
6059 add_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));
6060 add_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));
6061 add_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));
6062 add_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));
6063 add_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));
6064 add_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));
6065 add_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));
6066 add_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));
6067 add_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));
6068 add_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));
6069 add_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));
6070 add_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));
6071 add_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));
6072 add_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));
6073 add_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));
6074 add_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));
6075 add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
6076 add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
6077 add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
6078 add_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));
6079 add_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));
6080 add_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));
6081 add_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));
6082 add_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));
6083 add_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));
6084 add_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));
6085 add_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));
6086 add_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));
6087 add_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));
6088 add_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));
6089 add_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));
6090 add_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));
6091 add_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));
6092 add_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));
6093 add_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));
6094 add_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));
6095 add_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));
6096 add_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));
6097 add_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));
6098 add_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));
6099 add_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));
6100 add_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));
6101 add_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));
6102 add_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));
6103 add_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));
6104 add_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));
6105 add_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));
6106 add_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));
6107 add_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));
6108 add_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));
6109 add_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));
6110 add_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));
6111 add_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));
6112 add_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));
6113 add_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));
6114 add_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));
6115 add_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));
6116 add_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));
6117 add_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));
6118 add_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));
6119 add_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));
6120 add_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));
6121 add_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));
6122
6123 add_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));
6124 add_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));
6125 add_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));
6126 add_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));
6127 add_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));
6128 add_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));
6129 add_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));
6130 add_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));
6131 add_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));
6132 add_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));
6133 add_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));
6134 add_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));
6135 add_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));
6136 add_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));
6137 add_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));
6138
6139 add_options.push_back(AddOption("Vector2Constant", "Vector/Variables", "VisualShaderNodeVec2Constant", TTR("2D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
6140 add_options.push_back(AddOption("Vector2Parameter", "Vector/Variables", "VisualShaderNodeVec2Parameter", TTR("2D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
6141 add_options.push_back(AddOption("Vector3Constant", "Vector/Variables", "VisualShaderNodeVec3Constant", TTR("3D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
6142 add_options.push_back(AddOption("Vector3Parameter", "Vector/Variables", "VisualShaderNodeVec3Parameter", TTR("3D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
6143 add_options.push_back(AddOption("Vector4Constant", "Vector/Variables", "VisualShaderNodeVec4Constant", TTR("4D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
6144 add_options.push_back(AddOption("Vector4Parameter", "Vector/Variables", "VisualShaderNodeVec4Parameter", TTR("4D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
6145
6146 // SPECIAL
6147
6148 add_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.")));
6149 add_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.")));
6150 add_options.push_back(AddOption("ParameterRef", "Special", "VisualShaderNodeParameterRef", TTR("A reference to an existing parameter.")));
6151 add_options.push_back(AddOption("VaryingGetter", "Special", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
6152 add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
6153 add_options.push_back(AddOption("VaryingGetter", "Special", "VisualShaderNodeVaryingGetter", TTR("Get varying parameter."), {}, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
6154 add_options.push_back(AddOption("VaryingSetter", "Special", "VisualShaderNodeVaryingSetter", TTR("Set varying parameter."), {}, -1, TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
6155
6156 custom_node_option_idx = add_options.size();
6157
6158 /////////////////////////////////////////////////////////////////////
6159
6160 Ref<VisualShaderNodePluginDefault> default_plugin;
6161 default_plugin.instantiate();
6162 default_plugin->set_editor(this);
6163 add_plugin(default_plugin);
6164
6165 graph_plugin.instantiate();
6166 graph_plugin->set_editor(this);
6167
6168 property_editor_popup = memnew(PopupPanel);
6169 property_editor_popup->set_min_size(Size2(180, 0) * EDSCALE);
6170 add_child(property_editor_popup);
6171
6172 edited_property_holder.instantiate();
6173}
6174
6175class VisualShaderNodePluginInputEditor : public OptionButton {
6176 GDCLASS(VisualShaderNodePluginInputEditor, OptionButton);
6177
6178 VisualShaderEditor *editor = nullptr;
6179 Ref<VisualShaderNodeInput> input;
6180
6181public:
6182 void _notification(int p_what) {
6183 switch (p_what) {
6184 case NOTIFICATION_READY: {
6185 connect("item_selected", callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected));
6186 } break;
6187 }
6188 }
6189
6190 void _item_selected(int p_item) {
6191 editor->call_deferred(SNAME("_input_select_item"), input, get_item_text(p_item));
6192 }
6193
6194 void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeInput> &p_input) {
6195 editor = p_editor;
6196 input = p_input;
6197 Ref<Texture2D> type_icon[] = {
6198 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),
6199 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),
6200 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),
6201 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),
6202 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),
6203 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),
6204 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),
6205 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),
6206 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),
6207 };
6208
6209 add_item("[None]");
6210 int to_select = -1;
6211 for (int i = 0; i < input->get_input_index_count(); i++) {
6212 if (input->get_input_name() == input->get_input_index_name(i)) {
6213 to_select = i + 1;
6214 }
6215 add_icon_item(type_icon[input->get_input_index_type(i)], input->get_input_index_name(i));
6216 }
6217
6218 if (to_select >= 0) {
6219 select(to_select);
6220 }
6221 }
6222};
6223
6224////////////////
6225
6226class VisualShaderNodePluginVaryingEditor : public OptionButton {
6227 GDCLASS(VisualShaderNodePluginVaryingEditor, OptionButton);
6228
6229 VisualShaderEditor *editor = nullptr;
6230 Ref<VisualShaderNodeVarying> varying;
6231
6232public:
6233 void _notification(int p_what) {
6234 if (p_what == NOTIFICATION_READY) {
6235 connect("item_selected", callable_mp(this, &VisualShaderNodePluginVaryingEditor::_item_selected));
6236 }
6237 }
6238
6239 void _item_selected(int p_item) {
6240 editor->call_deferred(SNAME("_varying_select_item"), varying, get_item_text(p_item));
6241 }
6242
6243 void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeVarying> &p_varying, VisualShader::Type p_type) {
6244 editor = p_editor;
6245 varying = p_varying;
6246
6247 Ref<Texture2D> type_icon[] = {
6248 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),
6249 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),
6250 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),
6251 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),
6252 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),
6253 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),
6254 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),
6255 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),
6256 };
6257
6258 bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
6259
6260 add_item("[None]");
6261
6262 int to_select = -1;
6263 for (int i = 0, j = 0; i < varying->get_varyings_count(); i++) {
6264 VisualShader::VaryingMode mode = varying->get_varying_mode_by_index(i);
6265 if (is_getter) {
6266 if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {
6267 if (p_type != VisualShader::TYPE_LIGHT) {
6268 j++;
6269 continue;
6270 }
6271 } else {
6272 if (p_type != VisualShader::TYPE_FRAGMENT && p_type != VisualShader::TYPE_LIGHT) {
6273 j++;
6274 continue;
6275 }
6276 }
6277 } else {
6278 if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT) {
6279 if (p_type != VisualShader::TYPE_FRAGMENT) {
6280 j++;
6281 continue;
6282 }
6283 } else {
6284 if (p_type != VisualShader::TYPE_VERTEX) {
6285 j++;
6286 continue;
6287 }
6288 }
6289 }
6290 if (varying->get_varying_name() == varying->get_varying_name_by_index(i)) {
6291 to_select = i - j + 1;
6292 }
6293 add_icon_item(type_icon[varying->get_varying_type_by_index(i)], varying->get_varying_name_by_index(i));
6294 }
6295
6296 if (to_select >= 0) {
6297 select(to_select);
6298 }
6299 }
6300};
6301
6302////////////////
6303
6304class VisualShaderNodePluginParameterRefEditor : public OptionButton {
6305 GDCLASS(VisualShaderNodePluginParameterRefEditor, OptionButton);
6306
6307 VisualShaderEditor *editor = nullptr;
6308 Ref<VisualShaderNodeParameterRef> parameter_ref;
6309
6310public:
6311 void _notification(int p_what) {
6312 switch (p_what) {
6313 case NOTIFICATION_READY: {
6314 connect("item_selected", callable_mp(this, &VisualShaderNodePluginParameterRefEditor::_item_selected));
6315 } break;
6316 }
6317 }
6318
6319 void _item_selected(int p_item) {
6320 editor->call_deferred(SNAME("_parameter_ref_select_item"), parameter_ref, get_item_text(p_item));
6321 }
6322
6323 void setup(VisualShaderEditor *p_editor, const Ref<VisualShaderNodeParameterRef> &p_parameter_ref) {
6324 editor = p_editor;
6325 parameter_ref = p_parameter_ref;
6326
6327 Ref<Texture2D> type_icon[] = {
6328 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),
6329 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),
6330 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),
6331 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),
6332 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),
6333 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),
6334 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),
6335 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),
6336 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Color"), EditorStringName(EditorIcons)),
6337 EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),
6338 };
6339
6340 add_item("[None]");
6341 int to_select = -1;
6342 for (int i = 0; i < p_parameter_ref->get_parameters_count(); i++) {
6343 if (p_parameter_ref->get_parameter_name() == p_parameter_ref->get_parameter_name_by_index(i)) {
6344 to_select = i + 1;
6345 }
6346 add_icon_item(type_icon[p_parameter_ref->get_parameter_type_by_index(i)], p_parameter_ref->get_parameter_name_by_index(i));
6347 }
6348
6349 if (to_select >= 0) {
6350 select(to_select);
6351 }
6352 }
6353};
6354
6355////////////////
6356
6357class VisualShaderNodePluginDefaultEditor : public VBoxContainer {
6358 GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer);
6359 VisualShaderEditor *editor = nullptr;
6360 Ref<Resource> parent_resource;
6361 int node_id = 0;
6362 VisualShader::Type shader_type;
6363
6364public:
6365 void _property_changed(const String &p_property, const Variant &p_value, const String &p_field = "", bool p_changing = false) {
6366 if (p_changing) {
6367 return;
6368 }
6369
6370 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
6371
6372 updating = true;
6373 undo_redo->create_action(vformat(TTR("Edit Visual Property: %s"), p_property), UndoRedo::MERGE_ENDS);
6374 undo_redo->add_do_property(node.ptr(), p_property, p_value);
6375 undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property));
6376
6377 if (p_value.get_type() == Variant::OBJECT) {
6378 Ref<Resource> prev_res = node->get(p_property);
6379 Ref<Resource> curr_res = p_value;
6380
6381 if (curr_res.is_null()) {
6382 undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());
6383 } else {
6384 undo_redo->add_do_method(this, "_open_inspector", (Ref<Resource>)curr_res.ptr());
6385 }
6386 if (!prev_res.is_null()) {
6387 undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)prev_res.ptr());
6388 } else {
6389 undo_redo->add_undo_method(this, "_open_inspector", (Ref<Resource>)parent_resource.ptr());
6390 }
6391 }
6392 if (p_property != "constant") {
6393 VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();
6394 if (graph_plugin) {
6395 undo_redo->add_do_method(editor, "_update_next_previews", node_id);
6396 undo_redo->add_undo_method(editor, "_update_next_previews", node_id);
6397 undo_redo->add_do_method(graph_plugin, "update_node_deferred", shader_type, node_id);
6398 undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);
6399 }
6400 }
6401 undo_redo->commit_action();
6402
6403 updating = false;
6404 }
6405
6406 void _node_changed() {
6407 if (updating) {
6408 return;
6409 }
6410 for (int i = 0; i < properties.size(); i++) {
6411 properties[i]->update_property();
6412 }
6413 }
6414
6415 void _resource_selected(const String &p_path, Ref<Resource> p_resource) {
6416 _open_inspector(p_resource);
6417 }
6418
6419 void _open_inspector(Ref<Resource> p_resource) {
6420 InspectorDock::get_inspector_singleton()->edit(p_resource.ptr());
6421 }
6422
6423 bool updating = false;
6424 Ref<VisualShaderNode> node;
6425 Vector<EditorProperty *> properties;
6426 Vector<Label *> prop_names;
6427
6428 void _show_prop_names(bool p_show) {
6429 for (int i = 0; i < prop_names.size(); i++) {
6430 prop_names[i]->set_visible(p_show);
6431 }
6432 }
6433
6434 void setup(VisualShaderEditor *p_editor, Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, const HashMap<StringName, String> &p_overrided_names, Ref<VisualShaderNode> p_node) {
6435 editor = p_editor;
6436 parent_resource = p_parent_resource;
6437 updating = false;
6438 node = p_node;
6439 properties = p_properties;
6440
6441 node_id = (int)p_node->get_meta("id");
6442 shader_type = VisualShader::Type((int)p_node->get_meta("shader_type"));
6443
6444 for (int i = 0; i < p_properties.size(); i++) {
6445 HBoxContainer *hbox = memnew(HBoxContainer);
6446 hbox->set_h_size_flags(SIZE_EXPAND_FILL);
6447 add_child(hbox);
6448
6449 Label *prop_name = memnew(Label);
6450 String prop_name_str = p_names[i];
6451 if (p_overrided_names.has(p_names[i])) {
6452 prop_name_str = p_overrided_names[p_names[i]] + ":";
6453 } else {
6454 prop_name_str = prop_name_str.capitalize() + ":";
6455 }
6456 prop_name->set_text(prop_name_str);
6457 prop_name->set_visible(false);
6458 hbox->add_child(prop_name);
6459 prop_names.push_back(prop_name);
6460
6461 p_properties[i]->set_h_size_flags(SIZE_EXPAND_FILL);
6462 hbox->add_child(p_properties[i]);
6463
6464 bool res_prop = Object::cast_to<EditorPropertyResource>(p_properties[i]);
6465 if (res_prop) {
6466 p_properties[i]->connect("resource_selected", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_resource_selected));
6467 }
6468
6469 properties[i]->connect("property_changed", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_property_changed));
6470 properties[i]->set_object_and_property(node.ptr(), p_names[i]);
6471 properties[i]->update_property();
6472 properties[i]->set_name_split_ratio(0);
6473 }
6474 node->connect_changed(callable_mp(this, &VisualShaderNodePluginDefaultEditor::_node_changed));
6475 }
6476
6477 static void _bind_methods() {
6478 ClassDB::bind_method("_open_inspector", &VisualShaderNodePluginDefaultEditor::_open_inspector); // Used by UndoRedo.
6479 ClassDB::bind_method("_show_prop_names", &VisualShaderNodePluginDefaultEditor::_show_prop_names); // Used with call_deferred.
6480 }
6481};
6482
6483Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {
6484 Ref<VisualShader> p_shader = Ref<VisualShader>(p_parent_resource.ptr());
6485
6486 if (p_shader.is_valid() && (p_node->is_class("VisualShaderNodeVaryingGetter") || p_node->is_class("VisualShaderNodeVaryingSetter"))) {
6487 VisualShaderNodePluginVaryingEditor *editor = memnew(VisualShaderNodePluginVaryingEditor);
6488 editor->setup(vseditor, p_node, p_shader->get_shader_type());
6489 return editor;
6490 }
6491
6492 if (p_node->is_class("VisualShaderNodeParameterRef")) {
6493 VisualShaderNodePluginParameterRefEditor *editor = memnew(VisualShaderNodePluginParameterRefEditor);
6494 editor->setup(vseditor, p_node);
6495 return editor;
6496 }
6497
6498 if (p_node->is_class("VisualShaderNodeInput")) {
6499 VisualShaderNodePluginInputEditor *editor = memnew(VisualShaderNodePluginInputEditor);
6500 editor->setup(vseditor, p_node);
6501 return editor;
6502 }
6503
6504 Vector<StringName> properties = p_node->get_editable_properties();
6505 if (properties.size() == 0) {
6506 return nullptr;
6507 }
6508
6509 List<PropertyInfo> props;
6510 p_node->get_property_list(&props);
6511
6512 Vector<PropertyInfo> pinfo;
6513
6514 for (const PropertyInfo &E : props) {
6515 for (int i = 0; i < properties.size(); i++) {
6516 if (E.name == String(properties[i])) {
6517 pinfo.push_back(E);
6518 }
6519 }
6520 }
6521
6522 if (pinfo.size() == 0) {
6523 return nullptr;
6524 }
6525
6526 properties.clear();
6527
6528 Ref<VisualShaderNode> node = p_node;
6529 Vector<EditorProperty *> editors;
6530
6531 for (int i = 0; i < pinfo.size(); i++) {
6532 EditorProperty *prop = EditorInspector::instantiate_property_editor(node.ptr(), pinfo[i].type, pinfo[i].name, pinfo[i].hint, pinfo[i].hint_string, pinfo[i].usage);
6533 if (!prop) {
6534 return nullptr;
6535 }
6536
6537 if (Object::cast_to<EditorPropertyResource>(prop)) {
6538 Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false);
6539 prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
6540 } else if (Object::cast_to<EditorPropertyTransform3D>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) {
6541 prop->set_custom_minimum_size(Size2(250 * EDSCALE, 0));
6542 } else if (Object::cast_to<EditorPropertyQuaternion>(prop)) {
6543 prop->set_custom_minimum_size(Size2(320 * EDSCALE, 0));
6544 } else if (Object::cast_to<EditorPropertyFloat>(prop)) {
6545 prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
6546 } else if (Object::cast_to<EditorPropertyEnum>(prop)) {
6547 prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
6548 Object::cast_to<EditorPropertyEnum>(prop)->set_option_button_clip(false);
6549 }
6550
6551 editors.push_back(prop);
6552 properties.push_back(pinfo[i].name);
6553 }
6554 VisualShaderNodePluginDefaultEditor *editor = memnew(VisualShaderNodePluginDefaultEditor);
6555 editor->setup(vseditor, p_parent_resource, editors, properties, p_node->get_editable_properties_names(), p_node);
6556 return editor;
6557}
6558
6559void EditorPropertyVisualShaderMode::_option_selected(int p_which) {
6560 Ref<VisualShader> visual_shader(Object::cast_to<VisualShader>(get_edited_object()));
6561 if (visual_shader->get_mode() == p_which) {
6562 return;
6563 }
6564
6565 ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_editor_data().get_editor_by_name("Shader"));
6566 if (!shader_editor) {
6567 return;
6568 }
6569 VisualShaderEditor *editor = shader_editor->get_visual_shader_editor(visual_shader);
6570 if (!editor) {
6571 return;
6572 }
6573
6574 EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
6575 undo_redo->create_action(TTR("Visual Shader Mode Changed"));
6576 //do is easy
6577 undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);
6578 undo_redo->add_undo_method(visual_shader.ptr(), "set_mode", visual_shader->get_mode());
6579
6580 undo_redo->add_do_method(editor, "_set_mode", p_which);
6581 undo_redo->add_undo_method(editor, "_set_mode", visual_shader->get_mode());
6582
6583 //now undo is hell
6584
6585 //1. restore connections to output
6586 for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
6587 VisualShader::Type type = VisualShader::Type(i);
6588 List<VisualShader::Connection> conns;
6589 visual_shader->get_node_connections(type, &conns);
6590 for (const VisualShader::Connection &E : conns) {
6591 if (E.to_node == VisualShader::NODE_ID_OUTPUT) {
6592 undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
6593 }
6594 }
6595 }
6596 //2. restore input indices
6597 for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
6598 VisualShader::Type type = VisualShader::Type(i);
6599 Vector<int> nodes = visual_shader->get_node_list(type);
6600 for (int j = 0; j < nodes.size(); j++) {
6601 Ref<VisualShaderNodeInput> input = visual_shader->get_node(type, nodes[j]);
6602 if (!input.is_valid()) {
6603 continue;
6604 }
6605
6606 undo_redo->add_undo_method(input.ptr(), "set_input_name", input->get_input_name());
6607 }
6608 }
6609
6610 //3. restore enums and flags
6611 List<PropertyInfo> props;
6612 visual_shader->get_property_list(&props);
6613
6614 for (const PropertyInfo &E : props) {
6615 if (E.name.begins_with("flags/") || E.name.begins_with("modes/")) {
6616 undo_redo->add_undo_property(visual_shader.ptr(), E.name, visual_shader->get(E.name));
6617 }
6618 }
6619
6620 //4. delete varyings (if needed)
6621 if (p_which == VisualShader::MODE_PARTICLES || p_which == VisualShader::MODE_SKY || p_which == VisualShader::MODE_FOG) {
6622 int var_count = visual_shader->get_varyings_count();
6623
6624 if (var_count > 0) {
6625 for (int i = 0; i < var_count; i++) {
6626 const VisualShader::Varying *var = visual_shader->get_varying_by_index(i);
6627 undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", var->name);
6628 undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", var->name, var->mode, var->type);
6629 }
6630
6631 undo_redo->add_do_method(editor, "_update_varyings");
6632 undo_redo->add_undo_method(editor, "_update_varyings");
6633 }
6634 }
6635
6636 undo_redo->add_do_method(editor, "_update_nodes");
6637 undo_redo->add_undo_method(editor, "_update_nodes");
6638
6639 undo_redo->add_do_method(editor, "_update_graph");
6640 undo_redo->add_undo_method(editor, "_update_graph");
6641
6642 undo_redo->commit_action();
6643}
6644
6645void EditorPropertyVisualShaderMode::update_property() {
6646 int which = get_edited_property_value();
6647 options->select(which);
6648}
6649
6650void EditorPropertyVisualShaderMode::setup(const Vector<String> &p_options) {
6651 for (int i = 0; i < p_options.size(); i++) {
6652 options->add_item(p_options[i], i);
6653 }
6654}
6655
6656void EditorPropertyVisualShaderMode::set_option_button_clip(bool p_enable) {
6657 options->set_clip_text(p_enable);
6658}
6659
6660void EditorPropertyVisualShaderMode::_bind_methods() {
6661}
6662
6663EditorPropertyVisualShaderMode::EditorPropertyVisualShaderMode() {
6664 options = memnew(OptionButton);
6665 options->set_clip_text(true);
6666 add_child(options);
6667 add_focusable(options);
6668 options->connect("item_selected", callable_mp(this, &EditorPropertyVisualShaderMode::_option_selected));
6669}
6670
6671bool EditorInspectorVisualShaderModePlugin::can_handle(Object *p_object) {
6672 return true; // Can handle everything.
6673}
6674
6675bool 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) {
6676 if (p_path == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) {
6677 EditorPropertyVisualShaderMode *mode_editor = memnew(EditorPropertyVisualShaderMode);
6678 Vector<String> options = p_hint_text.split(",");
6679 mode_editor->setup(options);
6680 add_property_editor(p_path, mode_editor);
6681
6682 return true;
6683 }
6684
6685 return false;
6686}
6687
6688//////////////////////////////////
6689
6690void VisualShaderNodePortPreview::_shader_changed() {
6691 if (!is_valid || shader.is_null()) {
6692 return;
6693 }
6694
6695 Vector<VisualShader::DefaultTextureParam> default_textures;
6696 String shader_code = shader->generate_preview_shader(type, node, port, default_textures);
6697
6698 Ref<Shader> preview_shader;
6699 preview_shader.instantiate();
6700 preview_shader->set_code(shader_code);
6701 for (int i = 0; i < default_textures.size(); i++) {
6702 for (int j = 0; j < default_textures[i].params.size(); j++) {
6703 preview_shader->set_default_texture_parameter(default_textures[i].name, default_textures[i].params[j], j);
6704 }
6705 }
6706
6707 Ref<ShaderMaterial> mat;
6708 mat.instantiate();
6709 mat->set_shader(preview_shader);
6710
6711 //find if a material is also being edited and copy parameters to this one
6712
6713 for (int i = EditorNode::get_singleton()->get_editor_selection_history()->get_path_size() - 1; i >= 0; i--) {
6714 Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_path_object(i));
6715 ShaderMaterial *src_mat;
6716 if (!object) {
6717 continue;
6718 }
6719 if (object->has_method("get_material_override")) { // trying getting material from MeshInstance
6720 src_mat = Object::cast_to<ShaderMaterial>(object->call("get_material_override"));
6721 } else if (object->has_method("get_material")) { // from CanvasItem/Node2D
6722 src_mat = Object::cast_to<ShaderMaterial>(object->call("get_material"));
6723 } else {
6724 src_mat = Object::cast_to<ShaderMaterial>(object);
6725 }
6726 if (src_mat && src_mat->get_shader().is_valid()) {
6727 List<PropertyInfo> params;
6728 src_mat->get_shader()->get_shader_uniform_list(&params);
6729 for (const PropertyInfo &E : params) {
6730 mat->set(E.name, src_mat->get(E.name));
6731 }
6732 }
6733 }
6734
6735 set_material(mat);
6736}
6737
6738void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid) {
6739 shader = p_shader;
6740 shader->connect_changed(callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);
6741 type = p_type;
6742 port = p_port;
6743 node = p_node;
6744 is_valid = p_is_valid;
6745 queue_redraw();
6746 _shader_changed();
6747}
6748
6749Size2 VisualShaderNodePortPreview::get_minimum_size() const {
6750 int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size");
6751 return Size2(port_preview_size, port_preview_size) * EDSCALE;
6752}
6753
6754void VisualShaderNodePortPreview::_notification(int p_what) {
6755 switch (p_what) {
6756 case NOTIFICATION_DRAW: {
6757 Vector<Vector2> points = {
6758 Vector2(),
6759 Vector2(get_size().width, 0),
6760 get_size(),
6761 Vector2(0, get_size().height)
6762 };
6763
6764 Vector<Vector2> uvs = {
6765 Vector2(0, 0),
6766 Vector2(1, 0),
6767 Vector2(1, 1),
6768 Vector2(0, 1)
6769 };
6770
6771 if (is_valid) {
6772 Vector<Color> colors = {
6773 Color(1, 1, 1, 1),
6774 Color(1, 1, 1, 1),
6775 Color(1, 1, 1, 1),
6776 Color(1, 1, 1, 1)
6777 };
6778 draw_primitive(points, colors, uvs);
6779 } else {
6780 Vector<Color> colors = {
6781 Color(0, 0, 0, 1),
6782 Color(0, 0, 0, 1),
6783 Color(0, 0, 0, 1),
6784 Color(0, 0, 0, 1)
6785 };
6786 draw_primitive(points, colors, uvs);
6787 }
6788
6789 } break;
6790 }
6791}
6792
6793void VisualShaderNodePortPreview::_bind_methods() {
6794}
6795
6796//////////////////////////////////
6797
6798String VisualShaderConversionPlugin::converts_to() const {
6799 return "Shader";
6800}
6801
6802bool VisualShaderConversionPlugin::handles(const Ref<Resource> &p_resource) const {
6803 Ref<VisualShader> vshader = p_resource;
6804 return vshader.is_valid();
6805}
6806
6807Ref<Resource> VisualShaderConversionPlugin::convert(const Ref<Resource> &p_resource) const {
6808 Ref<VisualShader> vshader = p_resource;
6809 ERR_FAIL_COND_V(!vshader.is_valid(), Ref<Resource>());
6810
6811 Ref<Shader> shader;
6812 shader.instantiate();
6813
6814 String code = vshader->get_code();
6815 shader->set_code(code);
6816
6817 return shader;
6818}
6819