Path: blob/master/editor/shader/shader_globals_editor.cpp
20907 views
/**************************************************************************/1/* shader_globals_editor.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "shader_globals_editor.h"3132#include "core/config/project_settings.h"33#include "editor/editor_node.h"34#include "editor/editor_undo_redo_manager.h"35#include "editor/inspector/editor_inspector.h"36#include "scene/gui/label.h"37#include "scene/gui/line_edit.h"38#include "scene/gui/margin_container.h"39#include "servers/rendering/shader_language.h"4041static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {42"bool",43"bvec2",44"bvec3",45"bvec4",46"int",47"ivec2",48"ivec3",49"ivec4",50"rect2i",51"uint",52"uvec2",53"uvec3",54"uvec4",55"float",56"vec2",57"vec3",58"vec4",59"color",60"rect2",61"mat2",62"mat3",63"mat4",64"transform_2d",65"transform",66"sampler2D",67"sampler2DArray",68"sampler3D",69"samplerCube",70"samplerExternalOES",71};7273class ShaderGlobalsEditorInterface : public Object {74GDCLASS(ShaderGlobalsEditorInterface, Object)7576void _set_var(const StringName &p_name, const Variant &p_value, const Variant &p_prev_value) {77EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();7879undo_redo->create_action(TTR("Set Shader Global Variable"));80undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value);81undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_prev_value);82RS::GlobalShaderParameterType type = RS::get_singleton()->global_shader_parameter_get_type(p_name);83Dictionary gv;84gv["type"] = global_var_type_names[type];85if (type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {86Ref<Resource> res = p_value;87if (res.is_valid()) {88gv["value"] = res->get_path();89} else {90gv["value"] = "";91}92} else {93gv["value"] = p_value;94}9596String path = "shader_globals/" + String(p_name);97undo_redo->add_do_property(ProjectSettings::get_singleton(), path, gv);98undo_redo->add_undo_property(ProjectSettings::get_singleton(), path, GLOBAL_GET(path));99undo_redo->add_do_method(this, "_var_changed");100undo_redo->add_undo_method(this, "_var_changed");101block_update = true;102undo_redo->commit_action();103block_update = false;104}105106void _var_changed() {107emit_signal(SNAME("var_changed"));108}109110protected:111static void _bind_methods() {112ClassDB::bind_method("_var_changed", &ShaderGlobalsEditorInterface::_var_changed);113ADD_SIGNAL(MethodInfo("var_changed"));114}115116bool _set(const StringName &p_name, const Variant &p_value) {117Variant existing = RS::get_singleton()->global_shader_parameter_get(p_name);118119if (existing.get_type() == Variant::NIL) {120return false;121}122123callable_mp(this, &ShaderGlobalsEditorInterface::_set_var).call_deferred(p_name, p_value, existing);124125return true;126}127128bool _get(const StringName &p_name, Variant &r_ret) const {129r_ret = RS::get_singleton()->global_shader_parameter_get(p_name);130return r_ret.get_type() != Variant::NIL;131}132void _get_property_list(List<PropertyInfo> *p_list) const {133Vector<StringName> variables;134variables = RS::get_singleton()->global_shader_parameter_get_list();135for (int i = 0; i < variables.size(); i++) {136PropertyInfo pinfo;137pinfo.name = variables[i];138139switch (RS::get_singleton()->global_shader_parameter_get_type(variables[i])) {140case RS::GLOBAL_VAR_TYPE_BOOL: {141pinfo.type = Variant::BOOL;142} break;143case RS::GLOBAL_VAR_TYPE_BVEC2: {144pinfo.type = Variant::INT;145pinfo.hint = PROPERTY_HINT_FLAGS;146pinfo.hint_string = "x,y";147} break;148case RS::GLOBAL_VAR_TYPE_BVEC3: {149pinfo.type = Variant::INT;150pinfo.hint = PROPERTY_HINT_FLAGS;151pinfo.hint_string = "x,y,z";152} break;153case RS::GLOBAL_VAR_TYPE_BVEC4: {154pinfo.type = Variant::INT;155pinfo.hint = PROPERTY_HINT_FLAGS;156pinfo.hint_string = "x,y,z,w";157} break;158case RS::GLOBAL_VAR_TYPE_INT: {159pinfo.type = Variant::INT;160} break;161case RS::GLOBAL_VAR_TYPE_IVEC2: {162pinfo.type = Variant::VECTOR2I;163} break;164case RS::GLOBAL_VAR_TYPE_IVEC3: {165pinfo.type = Variant::VECTOR3I;166} break;167case RS::GLOBAL_VAR_TYPE_IVEC4: {168pinfo.type = Variant::VECTOR4I;169} break;170case RS::GLOBAL_VAR_TYPE_RECT2I: {171pinfo.type = Variant::RECT2I;172} break;173case RS::GLOBAL_VAR_TYPE_UINT: {174pinfo.type = Variant::INT;175} break;176case RS::GLOBAL_VAR_TYPE_UVEC2: {177pinfo.type = Variant::VECTOR2I;178} break;179case RS::GLOBAL_VAR_TYPE_UVEC3: {180pinfo.type = Variant::VECTOR3I;181} break;182case RS::GLOBAL_VAR_TYPE_UVEC4: {183pinfo.type = Variant::VECTOR4I;184} break;185case RS::GLOBAL_VAR_TYPE_FLOAT: {186pinfo.type = Variant::FLOAT;187} break;188case RS::GLOBAL_VAR_TYPE_VEC2: {189pinfo.type = Variant::VECTOR2;190} break;191case RS::GLOBAL_VAR_TYPE_VEC3: {192pinfo.type = Variant::VECTOR3;193} break;194case RS::GLOBAL_VAR_TYPE_VEC4: {195pinfo.type = Variant::VECTOR4;196} break;197case RS::GLOBAL_VAR_TYPE_RECT2: {198pinfo.type = Variant::RECT2;199} break;200case RS::GLOBAL_VAR_TYPE_COLOR: {201pinfo.type = Variant::COLOR;202} break;203case RS::GLOBAL_VAR_TYPE_MAT2: {204pinfo.type = Variant::PACKED_FLOAT32_ARRAY;205} break;206case RS::GLOBAL_VAR_TYPE_MAT3: {207pinfo.type = Variant::BASIS;208} break;209case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {210pinfo.type = Variant::TRANSFORM2D;211} break;212case RS::GLOBAL_VAR_TYPE_TRANSFORM: {213pinfo.type = Variant::TRANSFORM3D;214} break;215case RS::GLOBAL_VAR_TYPE_MAT4: {216pinfo.type = Variant::PROJECTION;217} break;218case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {219pinfo.type = Variant::OBJECT;220pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;221pinfo.hint_string = "Texture2D";222} break;223case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {224pinfo.type = Variant::OBJECT;225pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;226pinfo.hint_string = "Texture2DArray,CompressedTexture2DArray";227} break;228case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {229pinfo.type = Variant::OBJECT;230pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;231pinfo.hint_string = "Texture3D";232} break;233case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {234pinfo.type = Variant::OBJECT;235pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;236pinfo.hint_string = "Cubemap,CompressedCubemap";237} break;238case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {239pinfo.type = Variant::OBJECT;240pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;241pinfo.hint_string = "ExternalTexture";242} break;243default: {244} break;245}246247p_list->push_back(pinfo);248}249}250251public:252bool block_update = false;253254ShaderGlobalsEditorInterface() {255}256};257258static Variant create_var(RS::GlobalShaderParameterType p_type) {259switch (p_type) {260case RS::GLOBAL_VAR_TYPE_BOOL: {261return false;262}263case RS::GLOBAL_VAR_TYPE_BVEC2: {264return 0; //bits265}266case RS::GLOBAL_VAR_TYPE_BVEC3: {267return 0; //bits268}269case RS::GLOBAL_VAR_TYPE_BVEC4: {270return 0; //bits271}272case RS::GLOBAL_VAR_TYPE_INT: {273return 0; //bits274}275case RS::GLOBAL_VAR_TYPE_IVEC2: {276return Vector2i();277}278case RS::GLOBAL_VAR_TYPE_IVEC3: {279return Vector3i();280}281case RS::GLOBAL_VAR_TYPE_IVEC4: {282return Vector4i();283}284case RS::GLOBAL_VAR_TYPE_RECT2I: {285return Rect2i();286}287case RS::GLOBAL_VAR_TYPE_UINT: {288return 0;289}290case RS::GLOBAL_VAR_TYPE_UVEC2: {291return Vector2i();292}293case RS::GLOBAL_VAR_TYPE_UVEC3: {294return Vector3i();295}296case RS::GLOBAL_VAR_TYPE_UVEC4: {297return Vector4i();298}299case RS::GLOBAL_VAR_TYPE_FLOAT: {300return 0.0;301}302case RS::GLOBAL_VAR_TYPE_VEC2: {303return Vector2();304}305case RS::GLOBAL_VAR_TYPE_VEC3: {306return Vector3();307}308case RS::GLOBAL_VAR_TYPE_VEC4: {309return Vector4();310}311case RS::GLOBAL_VAR_TYPE_RECT2: {312return Rect2();313}314case RS::GLOBAL_VAR_TYPE_COLOR: {315return Color();316}317case RS::GLOBAL_VAR_TYPE_MAT2: {318Vector<float> xform;319xform.resize(4);320xform.write[0] = 1;321xform.write[1] = 0;322xform.write[2] = 0;323xform.write[3] = 1;324return xform;325}326case RS::GLOBAL_VAR_TYPE_MAT3: {327return Basis();328}329case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {330return Transform2D();331}332case RS::GLOBAL_VAR_TYPE_TRANSFORM: {333return Transform3D();334}335case RS::GLOBAL_VAR_TYPE_MAT4: {336return Projection();337}338case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {339return "";340}341case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {342return "";343}344case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {345return "";346}347case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {348return "";349}350case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {351return "";352}353default: {354return Variant();355}356}357}358359String ShaderGlobalsEditor::_check_new_variable_name(const String &p_variable_name) {360if (p_variable_name.is_empty()) {361return TTRC("Name cannot be empty.");362}363364if (!p_variable_name.is_valid_ascii_identifier()) {365return TTRC("Name must be a valid identifier.");366}367368return "";369}370371LineEdit *ShaderGlobalsEditor::get_name_box() const {372return variable_name;373}374375void ShaderGlobalsEditor::_variable_name_text_changed(const String &p_variable_name) {376const String &warning = _check_new_variable_name(p_variable_name.strip_edges());377variable_add->set_tooltip_text(warning);378variable_add->set_disabled(!warning.is_empty());379}380381void ShaderGlobalsEditor::_variable_added() {382String var = variable_name->get_text().strip_edges();383384if (RenderingServer::get_singleton()->global_shader_parameter_get(var).get_type() != Variant::NIL) {385EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists."), var));386return;387}388389List<String> keywords;390ShaderLanguage::get_keyword_list(&keywords);391392if (keywords.find(var) != nullptr || var == "script") {393EditorNode::get_singleton()->show_warning(vformat(TTR("Name '%s' is a reserved shader language keyword."), var));394return;395}396397EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();398399Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected()));400401undo_redo->create_action(TTR("Add Shader Global Parameter"));402undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_add", var, RS::GlobalShaderParameterType(variable_type->get_selected()), value);403undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_remove", var);404Dictionary gv;405gv["type"] = global_var_type_names[variable_type->get_selected()];406gv["value"] = value;407408undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + var, gv);409undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + var, Variant());410undo_redo->add_do_method(this, "_changed");411undo_redo->add_undo_method(this, "_changed");412undo_redo->commit_action();413414variable_name->clear();415}416417void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {418EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();419420undo_redo->create_action(TTR("Add Shader Global Parameter"));421undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable);422undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_add", p_variable, RS::get_singleton()->global_shader_parameter_get_type(p_variable), RS::get_singleton()->global_shader_parameter_get(p_variable));423424undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, Variant());425undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, GLOBAL_GET("shader_globals/" + p_variable));426undo_redo->add_do_method(this, "_changed");427undo_redo->add_undo_method(this, "_changed");428undo_redo->commit_action();429}430431void ShaderGlobalsEditor::_changed() {432emit_signal(SNAME("globals_changed"));433if (!interface->block_update) {434interface->notify_property_list_changed();435}436}437438void ShaderGlobalsEditor::_bind_methods() {439ClassDB::bind_method("_changed", &ShaderGlobalsEditor::_changed);440ADD_SIGNAL(MethodInfo("globals_changed"));441}442443void ShaderGlobalsEditor::_notification(int p_what) {444switch (p_what) {445case NOTIFICATION_VISIBILITY_CHANGED: {446if (is_visible_in_tree()) {447inspector->edit(interface);448}449} break;450451case NOTIFICATION_THEME_CHANGED: {452variable_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));453} break;454455case NOTIFICATION_PREDELETE: {456inspector->edit(nullptr);457} break;458}459}460461ShaderGlobalsEditor::ShaderGlobalsEditor() {462ProjectSettings::get_singleton()->add_hidden_prefix("shader_globals/");463464HBoxContainer *add_menu_hb = memnew(HBoxContainer);465add_child(add_menu_hb);466467add_menu_hb->add_child(memnew(Label(TTRC("Name:"))));468variable_name = memnew(LineEdit);469variable_name->set_h_size_flags(SIZE_EXPAND_FILL);470variable_name->set_clear_button_enabled(true);471variable_name->connect(SceneStringName(text_changed), callable_mp(this, &ShaderGlobalsEditor::_variable_name_text_changed));472variable_name->connect(SceneStringName(text_submitted), callable_mp(this, &ShaderGlobalsEditor::_variable_added).unbind(1));473474add_menu_hb->add_child(variable_name);475476add_menu_hb->add_child(memnew(Label(TTRC("Type:"))));477variable_type = memnew(OptionButton);478variable_type->set_h_size_flags(SIZE_EXPAND_FILL);479add_menu_hb->add_child(variable_type);480481for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {482variable_type->add_item(global_var_type_names[i]);483}484485variable_add = memnew(Button(TTRC("Add")));486variable_add->set_disabled(true);487add_menu_hb->add_child(variable_add);488variable_add->connect(SceneStringName(pressed), callable_mp(this, &ShaderGlobalsEditor::_variable_added));489490MarginContainer *mc = memnew(MarginContainer);491mc->set_theme_type_variation("NoBorderHorizontalBottomWide");492mc->set_v_size_flags(SIZE_EXPAND_FILL);493add_child(mc);494495inspector = memnew(EditorInspector);496inspector->set_use_wide_editors(true);497inspector->set_property_name_style(EditorPropertyNameProcessor::STYLE_RAW);498inspector->set_use_deletable_properties(true);499inspector->set_scroll_hint_mode(ScrollContainer::SCROLL_HINT_MODE_TOP_AND_LEFT);500mc->add_child(inspector);501inspector->connect("property_deleted", callable_mp(this, &ShaderGlobalsEditor::_variable_deleted), CONNECT_DEFERRED);502503interface = memnew(ShaderGlobalsEditorInterface);504interface->connect("var_changed", callable_mp(this, &ShaderGlobalsEditor::_changed));505}506507ShaderGlobalsEditor::~ShaderGlobalsEditor() {508memdelete(interface);509}510511512