diff --git a/doc/classes/VisualShaderNodeCustom.xml b/doc/classes/VisualShaderNodeCustom.xml index 7b992abe242..0a962a4aa44 100644 --- a/doc/classes/VisualShaderNodeCustom.xml +++ b/doc/classes/VisualShaderNodeCustom.xml @@ -44,6 +44,17 @@ Defining this method is [b]optional[/b]. + + + + + + Override this method to add a shader code to the beginning of each shader function (once). The shader code should be returned as a string, which can have multiple lines (the [code]"""[/code] multiline string construct can be used for convenience). + If there are multiple custom nodes of different types which use this feature the order of each insertion is undefined. + You can customize the generated code based on the shader [code]mode[/code] (see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader.Type]). + Defining this method is [b]optional[/b]. + + @@ -114,11 +125,20 @@ Defining this method is [b]optional[/b]. If not overridden, no return icon is shown. + + + + + + Override this method to prevent the node to be visible in the member dialog for the certain [code]mode[/code] (see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader.Type]). + Defining this method is [b]optional[/b]. If not overridden, it's [code]true[/code]. + + Override this method to enable high-end mark in the Visual Shader Editor's members dialog. - Defining this method is [b]optional[/b]. If not overridden, it's false. + Defining this method is [b]optional[/b]. If not overridden, it's [code]false[/code]. diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 94906acb63f..7f30dd91e53 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1082,6 +1082,10 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } } +void VisualShaderEditor::update_nodes() { + _update_nodes(); +} + void VisualShaderEditor::add_plugin(const Ref &p_plugin) { if (plugins.has(p_plugin)) { return; @@ -1165,10 +1169,7 @@ bool VisualShaderEditor::_is_available(int p_mode) { return (p_mode == -1 || (p_mode & current_mode) != 0); } -void VisualShaderEditor::update_custom_nodes() { - if (members_dialog->is_visible()) { - return; - } +void VisualShaderEditor::_update_nodes() { clear_custom_types(); List class_list; ScriptServer::get_global_class_list(&class_list); @@ -1184,6 +1185,9 @@ void VisualShaderEditor::update_custom_nodes() { Ref ref; ref.instantiate(); ref->set_script(script); + if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { + continue; + } String name; if (ref->has_method("_get_name")) { @@ -1240,6 +1244,32 @@ void VisualShaderEditor::update_custom_nodes() { } } + // Disables not-supported copied items. + { + for (CopyItem &item : copy_items_buffer) { + Ref custom = Object::cast_to(item.node.ptr()); + + if (custom.is_valid()) { + if (!custom->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { + item.disabled = true; + } else { + item.disabled = false; + } + } else { + for (int i = 0; i < add_options.size(); i++) { + if (add_options[i].type == item.node->get_class_name()) { + if ((add_options[i].func != visual_shader->get_mode() && add_options[i].func != -1) || !_is_available(add_options[i].mode)) { + item.disabled = true; + } else { + item.disabled = false; + } + break; + } + } + } + } + } + Array keys = added.keys(); keys.sort(); @@ -3370,15 +3400,23 @@ void VisualShaderEditor::_graph_gui_input(const Ref &p_event) { selected_float_constant = -1; } - if (to_change.is_empty() && copy_items_buffer.is_empty()) { + bool copy_buffer_empty = true; + for (const CopyItem &item : copy_items_buffer) { + if (!item.disabled) { + copy_buffer_empty = false; + break; + } + } + + if (to_change.is_empty() && copy_buffer_empty) { _show_members_dialog(true); } else { popup_menu->set_item_disabled(NodeMenuOptions::CUT, to_change.is_empty()); popup_menu->set_item_disabled(NodeMenuOptions::COPY, to_change.is_empty()); - popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_items_buffer.is_empty()); + popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_buffer_empty); popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.is_empty()); popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.is_empty()); - popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_items_buffer.is_empty()); + popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_buffer_empty); int temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR2); if (temp != -1) { @@ -3715,6 +3753,17 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, List &r_items, c if (p_duplicate) { undo_redo->create_action(TTR("Duplicate VisualShader Node(s)")); } else { + bool copy_buffer_empty = true; + for (const CopyItem &item : copy_items_buffer) { + if (!item.disabled) { + copy_buffer_empty = false; + break; + } + } + if (copy_buffer_empty) { + return; + } + undo_redo->create_action(TTR("Paste VisualShader Node(s)")); } @@ -3727,16 +3776,7 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, List &r_items, c Set added_set; for (CopyItem &item : r_items) { - bool unsupported = false; - for (int i = 0; i < add_options.size(); i++) { - if (add_options[i].type == item.node->get_class_name()) { - if (!_is_available(add_options[i].mode)) { - unsupported = true; - } - break; - } - } - if (unsupported) { + if (item.disabled) { unsupported_set.insert(item.id); continue; } @@ -3777,7 +3817,10 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, List &r_items, c } id_from = base_id; - for (int i = 0; i < r_items.size(); i++) { + for (const CopyItem &item : r_items) { + if (item.disabled) { + continue; + } undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from); undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_from); id_from++; @@ -3878,7 +3921,7 @@ void VisualShaderEditor::_mode_selected(int p_id) { } visual_shader->set_shader_type(VisualShader::Type(p_id + offset)); - _update_options_menu(); + _update_nodes(); _update_graph(); graph->grab_focus(); @@ -4465,8 +4508,8 @@ void VisualShaderEditor::_visibility_changed() { } void VisualShaderEditor::_bind_methods() { + ClassDB::bind_method("_update_nodes", &VisualShaderEditor::_update_nodes); ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); - ClassDB::bind_method("_update_options_menu", &VisualShaderEditor::_update_options_menu); ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node); ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed); ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item); @@ -5439,7 +5482,7 @@ void VisualShaderEditorPlugin::make_visible(bool p_visible) { //editor->animation_panel_make_visible(true); button->show(); EditorNode::get_singleton()->make_bottom_panel_item_visible(visual_shader_editor); - visual_shader_editor->update_custom_nodes(); + visual_shader_editor->update_nodes(); visual_shader_editor->set_process_input(true); //visual_shader_editor->set_process(true); } else { @@ -5919,8 +5962,8 @@ void EditorPropertyShaderMode::_option_selected(int p_which) { } } - undo_redo->add_do_method(editor, "_update_options_menu"); - undo_redo->add_undo_method(editor, "_update_options_menu"); + undo_redo->add_do_method(editor, "_update_nodes"); + undo_redo->add_undo_method(editor, "_update_nodes"); undo_redo->add_do_method(editor, "_update_graph"); undo_redo->add_undo_method(editor, "_update_graph"); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index e26b606397c..4087fc583c6 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -262,6 +262,7 @@ class VisualShaderEditor : public VBoxContainer { void _show_add_varying_dialog(); void _show_remove_varying_dialog(); + void _update_nodes(); void _update_graph(); struct AddOption { @@ -394,6 +395,7 @@ class VisualShaderEditor : public VBoxContainer { String group_inputs; String group_outputs; String expression; + bool disabled = false; }; void _dup_copy_nodes(int p_type, List &r_nodes, List &r_connections); @@ -476,7 +478,7 @@ protected: static void _bind_methods(); public: - void update_custom_nodes(); + void update_nodes(); void add_plugin(const Ref &p_plugin); void remove_plugin(const Ref &p_plugin); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 03b768e8690..d3e61dbc84b 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -455,32 +455,69 @@ String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader:: for (int i = 0; i < get_output_port_count(); i++) { output_vars.push_back(p_output_vars[i]); } - String code = " {\n"; + String _code; GDVIRTUAL_CALL(_get_code, input_vars, output_vars, p_mode, p_type, _code); - bool nend = _code.ends_with("\n"); - _code = _code.insert(0, " "); - _code = _code.replace("\n", "\n "); - code += _code; - if (!nend) { - code += "\n }"; - } else { - code.remove_at(code.size() - 1); - code += "}"; - } - code += "\n"; - return code; -} - -String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, int p_id) const { - String ret; - if (GDVIRTUAL_CALL(_get_global_code, p_mode, ret)) { - String code = "// " + get_caption() + "\n"; - code += ret; + if (_is_valid_code(_code)) { + String code = " {\n"; + bool nend = _code.ends_with("\n"); + _code = _code.insert(0, " "); + _code = _code.replace("\n", "\n "); + code += _code; + if (!nend) { + code += "\n }"; + } else { + code.remove_at(code.size() - 1); + code += "}"; + } code += "\n"; return code; } - return ""; + return String(); +} + +String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, int p_id) const { + String _code; + if (GDVIRTUAL_CALL(_get_global_code, p_mode, _code)) { + if (_is_valid_code(_code)) { + String code = "// " + get_caption() + "\n"; + code += _code; + code += "\n"; + return code; + } + } + return String(); +} + +String VisualShaderNodeCustom::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String _code; + if (GDVIRTUAL_CALL(_get_func_code, p_mode, p_type, _code)) { + if (_is_valid_code(_code)) { + bool nend = _code.ends_with("\n"); + String code = "// " + get_caption() + "\n"; + code += " {\n"; + _code = _code.insert(0, " "); + _code = _code.replace("\n", "\n "); + code += _code; + if (!nend) { + code += "\n }"; + } else { + code.remove_at(code.size() - 1); + code += "}"; + } + code += "\n"; + return code; + } + } + return String(); +} + +bool VisualShaderNodeCustom::is_available(Shader::Mode p_mode, VisualShader::Type p_type) const { + bool ret; + if (GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret)) { + return ret; + } + return true; } void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) { @@ -511,6 +548,13 @@ void VisualShaderNodeCustom::_set_input_port_default_value(int p_port, const Var VisualShaderNode::set_input_port_default_value(p_port, p_value); } +bool VisualShaderNodeCustom::_is_valid_code(const String &p_code) const { + if (p_code.is_empty() || p_code == "null") { + return false; + } + return true; +} + bool VisualShaderNodeCustom::_is_initialized() { return is_initialized; } @@ -531,8 +575,10 @@ void VisualShaderNodeCustom::_bind_methods() { GDVIRTUAL_BIND(_get_output_port_type, "port"); GDVIRTUAL_BIND(_get_output_port_name, "port"); GDVIRTUAL_BIND(_get_code, "input_vars", "output_vars", "mode", "type"); + GDVIRTUAL_BIND(_get_func_code, "mode", "type"); GDVIRTUAL_BIND(_get_global_code, "mode"); GDVIRTUAL_BIND(_is_highend); + GDVIRTUAL_BIND(_is_available, "mode", "type"); ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized); ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 5cad5fc95b4..2d4b2852e93 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -383,14 +383,20 @@ protected: GDVIRTUAL1RC(int, _get_output_port_type, int) GDVIRTUAL1RC(String, _get_output_port_name, int) GDVIRTUAL4RC(String, _get_code, TypedArray, TypedArray, Shader::Mode, VisualShader::Type) + GDVIRTUAL2RC(String, _get_func_code, Shader::Mode, VisualShader::Type) GDVIRTUAL1RC(String, _get_global_code, Shader::Mode) GDVIRTUAL0RC(bool, _is_highend) + GDVIRTUAL2RC(bool, _is_available, Shader::Mode, VisualShader::Type) + + bool _is_valid_code(const String &p_code) const; protected: void _set_input_port_default_value(int p_port, const Variant &p_value); + bool is_available(Shader::Mode p_mode, VisualShader::Type p_type) const; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override; + virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; static void _bind_methods(); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index a6aa6d8c49b..7b4d7e66d40 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -5696,7 +5696,7 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port) String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const { String code; - code += "// TRIPLANAR FUNCTION GLOBAL CODE\n"; + code += "// " + get_caption() + "\n"; code += " vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n"; code += " vec4 samp = vec4(0.0);\n"; code += " samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n"; @@ -5719,11 +5719,13 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader: String code; if (p_type == VisualShader::TYPE_VERTEX) { - code += " // TRIPLANAR FUNCTION VERTEX CODE\n"; + code += "// " + get_caption() + "\n"; + code += " {\n"; code += " triplanar_power_normal = pow(abs(NORMAL), vec3(triplanar_sharpness));\n"; code += " triplanar_power_normal /= dot(triplanar_power_normal, vec3(1.0));\n"; code += " triplanar_pos = VERTEX * triplanar_scale + triplanar_offset;\n"; code += " triplanar_pos *= vec3(1.0, -1.0, 1.0);\n"; + code += " }\n"; } return code;