diff --git a/editor/docks/filesystem_dock.cpp b/editor/docks/filesystem_dock.cpp index 5743351748a..79c1ae76e48 100644 --- a/editor/docks/filesystem_dock.cpp +++ b/editor/docks/filesystem_dock.cpp @@ -2711,17 +2711,17 @@ void FileSystemDock::_resource_created() { fpath = fpath.get_base_dir(); } - String type_name = new_resource_dialog->get_selected_type(); + const String type_name = new_resource_dialog->get_selected_type(); if (type_name == "Shader") { - make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 0); - make_shader_dialog->popup_centered(); - return; - } else if (type_name == "VisualShader") { - make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 1); + make_shader_dialog->config(fpath.path_join("new_shader"), false, false, type_name); make_shader_dialog->popup_centered(); return; } else if (type_name == "ShaderInclude") { - make_shader_dialog->config(fpath.path_join("new_shader_include"), false, false, 2); + make_shader_dialog->config(fpath.path_join("new_shader_include"), false, false, type_name); + make_shader_dialog->popup_centered(); + return; + } else if (type_name == "VisualShader") { + make_shader_dialog->config(fpath.path_join("new_shader"), false, false, type_name); make_shader_dialog->popup_centered(); return; } diff --git a/editor/docks/scene_tree_dock.cpp b/editor/docks/scene_tree_dock.cpp index 9c0a463af89..6801f918ad0 100644 --- a/editor/docks/scene_tree_dock.cpp +++ b/editor/docks/scene_tree_dock.cpp @@ -4255,7 +4255,7 @@ void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) { shader_create_dialog->connect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created)); shader_create_dialog->connect(SceneStringName(confirmed), callable_mp(this, &SceneTreeDock::_shader_creation_closed)); shader_create_dialog->connect("canceled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); - shader_create_dialog->config(path, true, true, -1, p_preferred_mode); + shader_create_dialog->config(path, true, true, "", p_preferred_mode); shader_create_dialog->popup_centered(); } diff --git a/editor/shader/editor_shader_language_plugin.cpp b/editor/shader/editor_shader_language_plugin.cpp new file mode 100644 index 00000000000..0b77fe86f1b --- /dev/null +++ b/editor/shader/editor_shader_language_plugin.cpp @@ -0,0 +1,70 @@ +/**************************************************************************/ +/* editor_shader_language_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "editor_shader_language_plugin.h" + +Vector> EditorShaderLanguagePlugin::shader_languages; +Vector EditorShaderLanguagePlugin::language_variation_map; + +void EditorShaderLanguagePlugin::register_shader_language(const Ref &p_shader_language) { + // Allows one ShaderLanguageEditorPlugin to provide multiple dropdown options in + // the language selection menu. For example, ShaderInclude is handled this way. + // X is the plugin index, and Y is the language variation index. + for (int i = 0; i < p_shader_language->get_language_variations().size(); i++) { + language_variation_map.push_back(Vector2i(shader_languages.size(), i)); + } + shader_languages.push_back(p_shader_language); +} + +void EditorShaderLanguagePlugin::clear_registered_shader_languages() { + shader_languages.clear(); + language_variation_map.clear(); +} + +const Vector> EditorShaderLanguagePlugin::get_shader_languages_read_only() { + return shader_languages; +} + +int EditorShaderLanguagePlugin::get_shader_language_variation_count() { + return language_variation_map.size(); +} + +Ref EditorShaderLanguagePlugin::get_shader_language_for_index(int p_index) { + ERR_FAIL_INDEX_V(p_index, language_variation_map.size(), nullptr); + Vector2i lang_var_indices = language_variation_map[p_index]; + return shader_languages[lang_var_indices.x]; +} + +String EditorShaderLanguagePlugin::get_file_extension_for_index(int p_index) { + ERR_FAIL_INDEX_V(p_index, language_variation_map.size(), "tres"); + Vector2i lang_var_indices = language_variation_map[p_index]; + EditorShaderLanguagePlugin *lang = shader_languages[lang_var_indices.x].ptr(); + return lang->get_file_extension(lang_var_indices.y); +} diff --git a/editor/shader/editor_shader_language_plugin.h b/editor/shader/editor_shader_language_plugin.h new file mode 100644 index 00000000000..8cbba218b6e --- /dev/null +++ b/editor/shader/editor_shader_language_plugin.h @@ -0,0 +1,57 @@ +/**************************************************************************/ +/* editor_shader_language_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +#include "shader_editor.h" + +class EditorShaderLanguagePlugin : public RefCounted { + GDCLASS(EditorShaderLanguagePlugin, RefCounted); + + static Vector> shader_languages; + static Vector language_variation_map; + +public: + static void register_shader_language(const Ref &p_shader_language); + static void clear_registered_shader_languages(); + static const Vector> get_shader_languages_read_only(); + static int get_shader_language_variation_count(); + static Ref get_shader_language_for_index(int p_index); + static String get_file_extension_for_index(int p_index); + + virtual bool handles_shader(const Ref &p_shader) const = 0; + virtual bool handles_shader_include(const Ref &p_shader_inc) const { return false; } + virtual ShaderEditor *edit_shader(const Ref &p_shader) = 0; + virtual ShaderEditor *edit_shader_include(const Ref &p_shader_inc) { return nullptr; } + virtual Ref create_new_shader(int p_variation_index, Shader::Mode p_shader_mode, int p_template_index) = 0; + virtual Ref create_new_shader_include() { return Ref(); } + virtual PackedStringArray get_language_variations() const = 0; + virtual String get_file_extension(int p_variation_index) const { return "tres"; } +}; diff --git a/editor/shader/shader_create_dialog.cpp b/editor/shader/shader_create_dialog.cpp index 12827beb8ee..106def21465 100644 --- a/editor/shader/shader_create_dialog.cpp +++ b/editor/shader/shader_create_dialog.cpp @@ -34,41 +34,21 @@ #include "editor/editor_node.h" #include "editor/gui/editor_file_dialog.h" #include "editor/gui/editor_validation_panel.h" +#include "editor/shader/editor_shader_language_plugin.h" #include "editor/themes/editor_scale.h" #include "scene/resources/shader_include.h" -#include "scene/resources/visual_shader.h" #include "servers/rendering/shader_types.h" -enum ShaderType { - SHADER_TYPE_TEXT, - SHADER_TYPE_VISUAL, - SHADER_TYPE_INC, - SHADER_TYPE_MAX, -}; - void ShaderCreateDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - String last_lang = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_language", ""); - if (!last_lang.is_empty()) { - for (int i = 0; i < type_menu->get_item_count(); i++) { - if (type_menu->get_item_text(i) == last_lang) { - type_menu->select(i); - current_type = i; - break; - } - } - } else { - type_menu->select(default_type); - } - current_mode = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_mode", 0); mode_menu->select(current_mode); } break; case NOTIFICATION_THEME_CHANGED: { - _refresh_type_icons(); path_button->set_button_icon(get_editor_theme_icon(SNAME("Folder"))); + // Note that some of the theme logic happens in `config()` when opening the dialog. } break; } } @@ -91,16 +71,13 @@ void ShaderCreateDialog::_refresh_type_icons() { void ShaderCreateDialog::_update_language_info() { type_data.clear(); - for (int i = 0; i < SHADER_TYPE_MAX; i++) { + for (int i = 0; i < EditorShaderLanguagePlugin::get_shader_language_variation_count(); i++) { ShaderTypeData shader_type_data; - if (i == int(SHADER_TYPE_TEXT)) { + if (i == 0) { + // HACK: The ShaderCreateDialog class currently only shows templates for text shaders. Generalize this later. shader_type_data.use_templates = true; - shader_type_data.default_extension = "gdshader"; - } else if (i == int(SHADER_TYPE_INC)) { - shader_type_data.default_extension = "gdshaderinc"; - } else { - shader_type_data.default_extension = "tres"; } + shader_type_data.default_extension = EditorShaderLanguagePlugin::get_file_extension_for_index(i); shader_type_data.extensions.push_back(shader_type_data.default_extension); if (shader_type_data.default_extension != "tres") { shader_type_data.extensions.push_back("tres"); @@ -155,93 +132,14 @@ void ShaderCreateDialog::_create_new() { Ref shader; Ref shader_inc; - switch (type_menu->get_selected()) { - case SHADER_TYPE_TEXT: { - Ref text_shader; - text_shader.instantiate(); - shader = text_shader; - - StringBuilder code; - code += vformat("shader_type %s;\n", mode_menu->get_text().to_snake_case()); - - if (current_template == 0) { // Default template. - switch (current_mode) { - case Shader::MODE_SPATIAL: - code += R"( -void vertex() { - // Called for every vertex the material is visible on. -} - -void fragment() { - // Called for every pixel the material is visible on. -} - -//void light() { -// // Called for every pixel for every light affecting the material. -// // Uncomment to replace the default light processing function with this one. -//} -)"; - break; - case Shader::MODE_CANVAS_ITEM: - code += R"( -void vertex() { - // Called for every vertex the material is visible on. -} - -void fragment() { - // Called for every pixel the material is visible on. -} - -//void light() { -// // Called for every pixel for every light affecting the CanvasItem. -// // Uncomment to replace the default light processing function with this one. -//} -)"; - break; - case Shader::MODE_PARTICLES: - code += R"( -void start() { - // Called when a particle is spawned. -} - -void process() { - // Called every frame on existing particles (according to the Fixed FPS property). -} -)"; - break; - case Shader::MODE_SKY: - code += R"( -void sky() { - // Called for every visible pixel in the sky background, as well as all pixels - // in the radiance cubemap. -} -)"; - break; - case Shader::MODE_FOG: - code += R"( -void fog() { - // Called once for every froxel that is touched by an axis-aligned bounding box - // of the associated FogVolume. This means that froxels that just barely touch - // a given FogVolume will still be used. -} -)"; - } - } - text_shader->set_code(code.as_string()); - } break; - case SHADER_TYPE_VISUAL: { - Ref visual_shader; - visual_shader.instantiate(); - shader = visual_shader; - visual_shader->set_mode(Shader::Mode(current_mode)); - } break; - case SHADER_TYPE_INC: { - Ref include; - include.instantiate(); - shader_inc = include; - } break; - default: { - } break; + const int type_index = type_menu->get_selected(); + Ref shader_lang = EditorShaderLanguagePlugin::get_shader_language_for_index(type_index); + // A bit of an unfortunate hack because Shader and ShaderInclude do not share a common base class. + // We need duplicate code paths for includes vs non-includes, so just check for the string "Include". + if (type_menu->get_item_text(type_index).contains("Include")) { + shader_inc = shader_lang->create_new_shader_include(); + } else { + shader = shader_lang->create_new_shader(0, Shader::Mode(current_mode), current_template); } if (shader.is_null()) { @@ -317,8 +215,18 @@ void ShaderCreateDialog::_type_changed(int p_language) { _path_changed(path); file_path->set_text(path); - type_menu->set_item_disabled(int(SHADER_TYPE_INC), load_enabled); - mode_menu->set_disabled(p_language == SHADER_TYPE_INC); + mode_menu->set_disabled(false); + for (int i = 0; i < type_menu->get_item_count(); i++) { + const String item_name = type_menu->get_item_text(i); + if (item_name.contains("Include")) { + type_menu->set_item_disabled(i, load_enabled); + if (i == p_language) { + mode_menu->set_disabled(true); + } + } else { + type_menu->set_item_disabled(i, false); + } + } template_menu->set_disabled(!shader_type_data.use_templates); template_menu->clear(); @@ -408,7 +316,43 @@ void ShaderCreateDialog::_path_submitted(const String &p_path) { } } -void ShaderCreateDialog::config(const String &p_base_path, bool p_built_in_enabled, bool p_load_enabled, int p_preferred_type, int p_preferred_mode) { +void ShaderCreateDialog::config(const String &p_base_path, bool p_built_in_enabled, bool p_load_enabled, const String &p_preferred_type, int p_preferred_mode) { + _update_language_info(); + type_menu->clear(); + const Vector> shader_langs = EditorShaderLanguagePlugin::get_shader_languages_read_only(); + ERR_FAIL_COND_MSG(shader_langs.is_empty(), "ShaderCreateDialog: Unable to load any shader languages!"); + for (Ref shader_lang : shader_langs) { + const PackedStringArray variations = shader_lang->get_language_variations(); + for (const String &variation : variations) { + type_menu->add_item(variation); + } + } + _refresh_type_icons(); + + int preferred_type = -1; + // Select preferred type if specified. + for (int i = 0; i < type_menu->get_item_count(); i++) { + if (type_menu->get_item_text(i) == p_preferred_type) { + preferred_type = i; + break; + } + } + if (preferred_type < 0 || preferred_type >= type_menu->get_item_count()) { + preferred_type = 0; + // Select the last selected language if possible, otherwise default to the first language. + String last_lang = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_language", ""); + if (!last_lang.is_empty()) { + for (int i = 0; i < type_menu->get_item_count(); i++) { + if (type_menu->get_item_text(i) == last_lang) { + preferred_type = i; + break; + } + } + } + } + type_menu->select(preferred_type); + current_type = 0; + if (!p_base_path.is_empty()) { initial_base_path = p_base_path.get_basename(); file_path->set_text(initial_base_path + "." + type_data.get(type_menu->get_selected()).default_extension); @@ -426,11 +370,6 @@ void ShaderCreateDialog::config(const String &p_base_path, bool p_built_in_enabl internal->set_pressed(EditorSettings::get_singleton()->get_project_metadata("shader_setup", "create_built_in_shader", false)); } - if (p_preferred_type > -1) { - type_menu->select(p_preferred_type); - _type_changed(p_preferred_type); - } - if (p_preferred_mode > -1) { mode_menu->select(p_preferred_mode); _mode_changed(p_preferred_mode); @@ -468,41 +407,14 @@ String ShaderCreateDialog::_validate_path(const String &p_path) { const ShaderCreateDialog::ShaderTypeData ¤t_type_data = type_data.get(current_type); const String file_extension = stripped_file_path.get_extension(); - HashSet extensions; - List::ConstIterator itr = type_data.begin(); - for (int i = 0; i < SHADER_TYPE_MAX; ++itr, ++i) { - for (const String &ext : itr->extensions) { - if (!extensions.has(ext)) { - extensions.insert(ext); - } + for (const String &type_ext : current_type_data.extensions) { + if (type_ext.nocasecmp_to(file_extension) == 0) { + return ""; } } - bool found = false; - bool match = false; - - for (const String &ext : extensions) { - if (ext.nocasecmp_to(file_extension) == 0) { - found = true; - for (const String &type_ext : current_type_data.extensions) { - if (type_ext.nocasecmp_to(file_extension) == 0) { - match = true; - break; - } - } - break; - } - } - - if (!found) { - return TTR("Invalid extension."); - } - if (!match) { - return TTR("Wrong extension chosen."); - } - - return ""; + return TTR("Invalid extension for selected shader type."); } void ShaderCreateDialog::_update_dialog() { @@ -598,36 +510,6 @@ ShaderCreateDialog::ShaderCreateDialog() { gc->add_child(memnew(Label(TTR("Type:")))); gc->add_child(type_menu); - for (int i = 0; i < SHADER_TYPE_MAX; i++) { - String type; - bool invalid = false; - switch (i) { - case SHADER_TYPE_TEXT: - type = "Shader"; - default_type = i; - break; - case SHADER_TYPE_VISUAL: - type = "VisualShader"; - break; - case SHADER_TYPE_INC: - type = "ShaderInclude"; - break; - case SHADER_TYPE_MAX: - invalid = true; - break; - default: - invalid = true; - break; - } - if (invalid) { - continue; - } - type_menu->add_item(type); - } - if (default_type >= 0) { - type_menu->select(default_type); - } - current_type = default_type; type_menu->connect(SceneStringName(item_selected), callable_mp(this, &ShaderCreateDialog::_type_changed)); // Modes. diff --git a/editor/shader/shader_create_dialog.h b/editor/shader/shader_create_dialog.h index d14bcafc309..cc59b48f108 100644 --- a/editor/shader/shader_create_dialog.h +++ b/editor/shader/shader_create_dialog.h @@ -78,7 +78,6 @@ class ShaderCreateDialog : public ConfirmationDialog { bool load_enabled = false; bool re_check_path = false; int current_type = -1; - int default_type = -1; int current_mode = 0; int current_template = 0; @@ -105,6 +104,6 @@ protected: static void _bind_methods(); public: - void config(const String &p_base_path, bool p_built_in_enabled = true, bool p_load_enabled = true, int p_preferred_type = -1, int p_preferred_mode = -1); + void config(const String &p_base_path, bool p_built_in_enabled = true, bool p_load_enabled = true, const String &p_preferred_type = "", int p_preferred_mode = -1); ShaderCreateDialog(); }; diff --git a/editor/shader/shader_editor_plugin.cpp b/editor/shader/shader_editor_plugin.cpp index 22ce5fa4ecf..c257374b146 100644 --- a/editor/shader/shader_editor_plugin.cpp +++ b/editor/shader/shader_editor_plugin.cpp @@ -40,7 +40,8 @@ #include "editor/settings/editor_command_palette.h" #include "editor/shader/shader_create_dialog.h" #include "editor/shader/text_shader_editor.h" -#include "editor/shader/visual_shader_editor_plugin.h" +#include "editor/shader/text_shader_language_plugin.h" +#include "editor/shader/visual_shader_language_plugin.h" #include "editor/themes/editor_scale.h" #include "scene/gui/item_list.h" #include "scene/gui/tab_container.h" @@ -151,8 +152,12 @@ void ShaderEditorPlugin::edit(Object *p_object) { } } es.shader_inc = Ref(shader_include); - es.shader_editor = memnew(TextShaderEditor); - es.shader_editor->edit_shader_include(shader_include); + for (Ref shader_lang : EditorShaderLanguagePlugin::get_shader_languages_read_only()) { + if (shader_lang->handles_shader_include(es.shader_inc)) { + es.shader_editor = shader_lang->edit_shader_include(es.shader_inc); + break; + } + } } else { // If it's not a ShaderInclude, check for Shader. Shader *shader = Object::cast_to(p_object); @@ -168,15 +173,15 @@ void ShaderEditorPlugin::edit(Object *p_object) { } // If we did not return, the shader needs to be opened in a new shader editor. es.shader = Ref(shader); - Ref vs = es.shader; - if (vs.is_valid()) { - es.shader_editor = memnew(VisualShaderEditor); - } else { - es.shader_editor = memnew(TextShaderEditor); + for (Ref shader_lang : EditorShaderLanguagePlugin::get_shader_languages_read_only()) { + if (shader_lang->handles_shader(es.shader)) { + es.shader_editor = shader_lang->edit_shader(es.shader); + break; + } } - es.shader_editor->edit_shader(es.shader); } + ERR_FAIL_NULL_MSG(es.shader_editor, "ShaderEditorPlugin: Unable to edit shader because no suitable editor was found."); // TextShaderEditor-specific setup code. TextShaderEditor *text_shader_editor = Object::cast_to(es.shader_editor); if (text_shader_editor) { @@ -511,12 +516,12 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) { switch (p_index) { case FILE_MENU_NEW: { String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir(); - shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 0); + shader_create_dialog->config(base_path.path_join("new_shader"), false, false, "Shader"); shader_create_dialog->popup_centered(); } break; case FILE_MENU_NEW_INCLUDE: { String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir(); - shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 2); + shader_create_dialog->config(base_path.path_join("new_shader"), false, false, "ShaderInclude"); shader_create_dialog->popup_centered(); } break; case FILE_MENU_OPEN: { @@ -927,9 +932,18 @@ ShaderEditorPlugin::ShaderEditorPlugin() { files_split->add_child(shader_create_dialog); shader_create_dialog->connect("shader_created", callable_mp(this, &ShaderEditorPlugin::_shader_created)); shader_create_dialog->connect("shader_include_created", callable_mp(this, &ShaderEditorPlugin::_shader_include_created)); + + Ref text_shader_lang; + text_shader_lang.instantiate(); + EditorShaderLanguagePlugin::register_shader_language(text_shader_lang); + + Ref visual_shader_lang; + visual_shader_lang.instantiate(); + EditorShaderLanguagePlugin::register_shader_language(visual_shader_lang); } ShaderEditorPlugin::~ShaderEditorPlugin() { + EditorShaderLanguagePlugin::clear_registered_shader_languages(); memdelete(file_menu); memdelete(make_floating); } diff --git a/editor/shader/shader_editor_plugin.h b/editor/shader/shader_editor_plugin.h index 7753f40f5c2..a1d082c31f9 100644 --- a/editor/shader/shader_editor_plugin.h +++ b/editor/shader/shader_editor_plugin.h @@ -39,10 +39,8 @@ class MenuButton; class ShaderCreateDialog; class ShaderEditor; class TabContainer; -class TextShaderEditor; class VBoxContainer; class HBoxContainer; -class VisualShaderEditor; class WindowWrapper; class ShaderEditorPlugin : public EditorPlugin { diff --git a/editor/shader/text_shader_language_plugin.cpp b/editor/shader/text_shader_language_plugin.cpp new file mode 100644 index 00000000000..530e8ab8054 --- /dev/null +++ b/editor/shader/text_shader_language_plugin.cpp @@ -0,0 +1,156 @@ +/**************************************************************************/ +/* text_shader_language_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "text_shader_language_plugin.h" + +#include "text_shader_editor.h" + +#include "core/string/string_builder.h" +#include "servers/rendering/shader_types.h" + +bool TextShaderLanguagePlugin::handles_shader(const Ref &p_shader) const { + // The text shader editor only edits the base Shader class, + // not classes that inherit from it like VisualShader. + return p_shader->get_class_name() == Shader::get_class_static(); +} + +bool TextShaderLanguagePlugin::handles_shader_include(const Ref &p_shader_inc) const { + return p_shader_inc->get_class_static() == ShaderInclude::get_class_static(); +} + +ShaderEditor *TextShaderLanguagePlugin::edit_shader(const Ref &p_shader) { + TextShaderEditor *editor = memnew(TextShaderEditor); + editor->edit_shader(p_shader); + return editor; +} + +ShaderEditor *TextShaderLanguagePlugin::edit_shader_include(const Ref &p_shader_inc) { + TextShaderEditor *editor = memnew(TextShaderEditor); + editor->edit_shader_include(p_shader_inc); + return editor; +} + +Ref TextShaderLanguagePlugin::create_new_shader(int p_variation_index, Shader::Mode p_shader_mode, int p_template_index) { + Ref shader; + shader.instantiate(); + + StringBuilder code; + const String &shader_type = ShaderTypes::get_singleton()->get_types_list().get(p_shader_mode); + code += vformat("shader_type %s;\n", shader_type); + + if (p_template_index == 0) { // Default template. + switch (p_shader_mode) { + case Shader::MODE_SPATIAL: { + code += R"( +void vertex() { + // Called for every vertex the material is visible on. +} + +void fragment() { + // Called for every pixel the material is visible on. +} + +//void light() { +// // Called for every pixel for every light affecting the material. +// // Uncomment to replace the default light processing function with this one. +//} +)"; + } break; + case Shader::MODE_CANVAS_ITEM: { + code += R"( +void vertex() { + // Called for every vertex the material is visible on. +} + +void fragment() { + // Called for every pixel the material is visible on. +} + +//void light() { +// // Called for every pixel for every light affecting the CanvasItem. +// // Uncomment to replace the default light processing function with this one. +//} +)"; + } break; + case Shader::MODE_PARTICLES: { + code += R"( +void start() { + // Called when a particle is spawned. +} + +void process() { + // Called every frame on existing particles (according to the Fixed FPS property). +} +)"; + } break; + case Shader::MODE_SKY: { + code += R"( +void sky() { + // Called for every visible pixel in the sky background, as well as all pixels + // in the radiance cubemap. +} +)"; + } break; + case Shader::MODE_FOG: { + code += R"( +void fog() { + // Called once for every froxel that is touched by an axis-aligned bounding box + // of the associated FogVolume. This means that froxels that just barely touch + // a given FogVolume will still be used. +} +)"; + } break; + case Shader::MODE_MAX: { + ERR_FAIL_V_MSG(Ref(), "Invalid shader mode for text shader editor."); + } break; + } + } + shader->set_code(code.as_string()); + return shader; +} + +Ref TextShaderLanguagePlugin::create_new_shader_include() { + Ref shader_inc; + shader_inc.instantiate(); + return shader_inc; +} + +PackedStringArray TextShaderLanguagePlugin::get_language_variations() const { + return PackedStringArray{ "Shader", "ShaderInclude" }; +} + +String TextShaderLanguagePlugin::get_file_extension(int p_variation_index) const { + if (p_variation_index == 0) { + return "gdshader"; + } else if (p_variation_index == 1) { + return "gdshaderinc"; + } + return "tres"; +} diff --git a/editor/shader/text_shader_language_plugin.h b/editor/shader/text_shader_language_plugin.h new file mode 100644 index 00000000000..f5c08241fdb --- /dev/null +++ b/editor/shader/text_shader_language_plugin.h @@ -0,0 +1,47 @@ +/**************************************************************************/ +/* text_shader_language_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +#include "editor/shader/editor_shader_language_plugin.h" + +class TextShaderLanguagePlugin : public EditorShaderLanguagePlugin { + GDCLASS(TextShaderLanguagePlugin, EditorShaderLanguagePlugin); + +public: + virtual bool handles_shader(const Ref &p_shader) const override; + virtual bool handles_shader_include(const Ref &p_shader_inc) const override; + virtual ShaderEditor *edit_shader(const Ref &p_shader) override; + virtual ShaderEditor *edit_shader_include(const Ref &p_shader_inc) override; + virtual Ref create_new_shader(int p_variation_index, Shader::Mode p_shader_mode, int p_template_index) override; + virtual Ref create_new_shader_include() override; + virtual PackedStringArray get_language_variations() const override; + virtual String get_file_extension(int p_variation_index) const override; +}; diff --git a/editor/shader/visual_shader_language_plugin.cpp b/editor/shader/visual_shader_language_plugin.cpp new file mode 100644 index 00000000000..2d4d86977c1 --- /dev/null +++ b/editor/shader/visual_shader_language_plugin.cpp @@ -0,0 +1,58 @@ +/**************************************************************************/ +/* visual_shader_language_plugin.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "visual_shader_language_plugin.h" + +#include "visual_shader_editor_plugin.h" + +bool VisualShaderLanguagePlugin::handles_shader(const Ref &p_shader) const { + return Object::cast_to(p_shader.ptr()) != nullptr; +} + +ShaderEditor *VisualShaderLanguagePlugin::edit_shader(const Ref &p_shader) { + const Ref shader = p_shader; + ERR_FAIL_COND_V(shader.is_null(), nullptr); + VisualShaderEditor *editor = memnew(VisualShaderEditor); + editor->edit_shader(shader); + return editor; +} + +Ref VisualShaderLanguagePlugin::create_new_shader(int p_variation_index, Shader::Mode p_shader_mode, int p_template_index) { + Ref shader; + shader.instantiate(); + shader->set_mode(p_shader_mode); + return shader; +} + +PackedStringArray VisualShaderLanguagePlugin::get_language_variations() const { + PackedStringArray variations; + variations.push_back("VisualShader"); + return variations; +} diff --git a/editor/shader/visual_shader_language_plugin.h b/editor/shader/visual_shader_language_plugin.h new file mode 100644 index 00000000000..fbff6bdc879 --- /dev/null +++ b/editor/shader/visual_shader_language_plugin.h @@ -0,0 +1,43 @@ +/**************************************************************************/ +/* visual_shader_language_plugin.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +#include "editor/shader/editor_shader_language_plugin.h" + +class VisualShaderLanguagePlugin : public EditorShaderLanguagePlugin { + GDCLASS(VisualShaderLanguagePlugin, EditorShaderLanguagePlugin); + +public: + virtual bool handles_shader(const Ref &p_shader) const override; + virtual ShaderEditor *edit_shader(const Ref &p_shader) override; + virtual Ref create_new_shader(int p_variation_index, Shader::Mode p_shader_mode, int p_template_index) override; + virtual PackedStringArray get_language_variations() const override; +};