Path: blob/master/editor/shader/shader_globals_editor.cpp
9896 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 "servers/rendering/shader_language.h"3940static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {41"bool",42"bvec2",43"bvec3",44"bvec4",45"int",46"ivec2",47"ivec3",48"ivec4",49"rect2i",50"uint",51"uvec2",52"uvec3",53"uvec4",54"float",55"vec2",56"vec3",57"vec4",58"color",59"rect2",60"mat2",61"mat3",62"mat4",63"transform_2d",64"transform",65"sampler2D",66"sampler2DArray",67"sampler3D",68"samplerCube",69"samplerExternalOES",70};7172class ShaderGlobalsEditorInterface : public Object {73GDCLASS(ShaderGlobalsEditorInterface, Object)7475void _set_var(const StringName &p_name, const Variant &p_value, const Variant &p_prev_value) {76EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();7778undo_redo->create_action(TTR("Set Shader Global Variable"));79undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value);80undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_prev_value);81RS::GlobalShaderParameterType type = RS::get_singleton()->global_shader_parameter_get_type(p_name);82Dictionary gv;83gv["type"] = global_var_type_names[type];84if (type >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) {85Ref<Resource> res = p_value;86if (res.is_valid()) {87gv["value"] = res->get_path();88} else {89gv["value"] = "";90}91} else {92gv["value"] = p_value;93}9495String path = "shader_globals/" + String(p_name);96undo_redo->add_do_property(ProjectSettings::get_singleton(), path, gv);97undo_redo->add_undo_property(ProjectSettings::get_singleton(), path, GLOBAL_GET(path));98undo_redo->add_do_method(this, "_var_changed");99undo_redo->add_undo_method(this, "_var_changed");100block_update = true;101undo_redo->commit_action();102block_update = false;103}104105void _var_changed() {106emit_signal(SNAME("var_changed"));107}108109protected:110static void _bind_methods() {111ClassDB::bind_method("_var_changed", &ShaderGlobalsEditorInterface::_var_changed);112ADD_SIGNAL(MethodInfo("var_changed"));113}114115bool _set(const StringName &p_name, const Variant &p_value) {116Variant existing = RS::get_singleton()->global_shader_parameter_get(p_name);117118if (existing.get_type() == Variant::NIL) {119return false;120}121122callable_mp(this, &ShaderGlobalsEditorInterface::_set_var).call_deferred(p_name, p_value, existing);123124return true;125}126127bool _get(const StringName &p_name, Variant &r_ret) const {128r_ret = RS::get_singleton()->global_shader_parameter_get(p_name);129return r_ret.get_type() != Variant::NIL;130}131void _get_property_list(List<PropertyInfo> *p_list) const {132Vector<StringName> variables;133variables = RS::get_singleton()->global_shader_parameter_get_list();134for (int i = 0; i < variables.size(); i++) {135PropertyInfo pinfo;136pinfo.name = variables[i];137138switch (RS::get_singleton()->global_shader_parameter_get_type(variables[i])) {139case RS::GLOBAL_VAR_TYPE_BOOL: {140pinfo.type = Variant::BOOL;141} break;142case RS::GLOBAL_VAR_TYPE_BVEC2: {143pinfo.type = Variant::INT;144pinfo.hint = PROPERTY_HINT_FLAGS;145pinfo.hint_string = "x,y";146} break;147case RS::GLOBAL_VAR_TYPE_BVEC3: {148pinfo.type = Variant::INT;149pinfo.hint = PROPERTY_HINT_FLAGS;150pinfo.hint_string = "x,y,z";151} break;152case RS::GLOBAL_VAR_TYPE_BVEC4: {153pinfo.type = Variant::INT;154pinfo.hint = PROPERTY_HINT_FLAGS;155pinfo.hint_string = "x,y,z,w";156} break;157case RS::GLOBAL_VAR_TYPE_INT: {158pinfo.type = Variant::INT;159} break;160case RS::GLOBAL_VAR_TYPE_IVEC2: {161pinfo.type = Variant::VECTOR2I;162} break;163case RS::GLOBAL_VAR_TYPE_IVEC3: {164pinfo.type = Variant::VECTOR3I;165} break;166case RS::GLOBAL_VAR_TYPE_IVEC4: {167pinfo.type = Variant::VECTOR4I;168} break;169case RS::GLOBAL_VAR_TYPE_RECT2I: {170pinfo.type = Variant::RECT2I;171} break;172case RS::GLOBAL_VAR_TYPE_UINT: {173pinfo.type = Variant::INT;174} break;175case RS::GLOBAL_VAR_TYPE_UVEC2: {176pinfo.type = Variant::VECTOR2I;177} break;178case RS::GLOBAL_VAR_TYPE_UVEC3: {179pinfo.type = Variant::VECTOR3I;180} break;181case RS::GLOBAL_VAR_TYPE_UVEC4: {182pinfo.type = Variant::VECTOR4I;183} break;184case RS::GLOBAL_VAR_TYPE_FLOAT: {185pinfo.type = Variant::FLOAT;186} break;187case RS::GLOBAL_VAR_TYPE_VEC2: {188pinfo.type = Variant::VECTOR2;189} break;190case RS::GLOBAL_VAR_TYPE_VEC3: {191pinfo.type = Variant::VECTOR3;192} break;193case RS::GLOBAL_VAR_TYPE_VEC4: {194pinfo.type = Variant::VECTOR4;195} break;196case RS::GLOBAL_VAR_TYPE_RECT2: {197pinfo.type = Variant::RECT2;198} break;199case RS::GLOBAL_VAR_TYPE_COLOR: {200pinfo.type = Variant::COLOR;201} break;202case RS::GLOBAL_VAR_TYPE_MAT2: {203pinfo.type = Variant::PACKED_FLOAT32_ARRAY;204} break;205case RS::GLOBAL_VAR_TYPE_MAT3: {206pinfo.type = Variant::BASIS;207} break;208case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {209pinfo.type = Variant::TRANSFORM2D;210} break;211case RS::GLOBAL_VAR_TYPE_TRANSFORM: {212pinfo.type = Variant::TRANSFORM3D;213} break;214case RS::GLOBAL_VAR_TYPE_MAT4: {215pinfo.type = Variant::PROJECTION;216} break;217case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {218pinfo.type = Variant::OBJECT;219pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;220pinfo.hint_string = "Texture2D";221} break;222case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {223pinfo.type = Variant::OBJECT;224pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;225pinfo.hint_string = "Texture2DArray,CompressedTexture2DArray";226} break;227case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {228pinfo.type = Variant::OBJECT;229pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;230pinfo.hint_string = "Texture3D";231} break;232case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {233pinfo.type = Variant::OBJECT;234pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;235pinfo.hint_string = "Cubemap,CompressedCubemap";236} break;237case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {238pinfo.type = Variant::OBJECT;239pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;240pinfo.hint_string = "ExternalTexture";241} break;242default: {243} break;244}245246p_list->push_back(pinfo);247}248}249250public:251bool block_update = false;252253ShaderGlobalsEditorInterface() {254}255};256257static Variant create_var(RS::GlobalShaderParameterType p_type) {258switch (p_type) {259case RS::GLOBAL_VAR_TYPE_BOOL: {260return false;261}262case RS::GLOBAL_VAR_TYPE_BVEC2: {263return 0; //bits264}265case RS::GLOBAL_VAR_TYPE_BVEC3: {266return 0; //bits267}268case RS::GLOBAL_VAR_TYPE_BVEC4: {269return 0; //bits270}271case RS::GLOBAL_VAR_TYPE_INT: {272return 0; //bits273}274case RS::GLOBAL_VAR_TYPE_IVEC2: {275return Vector2i();276}277case RS::GLOBAL_VAR_TYPE_IVEC3: {278return Vector3i();279}280case RS::GLOBAL_VAR_TYPE_IVEC4: {281return Vector4i();282}283case RS::GLOBAL_VAR_TYPE_RECT2I: {284return Rect2i();285}286case RS::GLOBAL_VAR_TYPE_UINT: {287return 0;288}289case RS::GLOBAL_VAR_TYPE_UVEC2: {290return Vector2i();291}292case RS::GLOBAL_VAR_TYPE_UVEC3: {293return Vector3i();294}295case RS::GLOBAL_VAR_TYPE_UVEC4: {296return Vector4i();297}298case RS::GLOBAL_VAR_TYPE_FLOAT: {299return 0.0;300}301case RS::GLOBAL_VAR_TYPE_VEC2: {302return Vector2();303}304case RS::GLOBAL_VAR_TYPE_VEC3: {305return Vector3();306}307case RS::GLOBAL_VAR_TYPE_VEC4: {308return Vector4();309}310case RS::GLOBAL_VAR_TYPE_RECT2: {311return Rect2();312}313case RS::GLOBAL_VAR_TYPE_COLOR: {314return Color();315}316case RS::GLOBAL_VAR_TYPE_MAT2: {317Vector<float> xform;318xform.resize(4);319xform.write[0] = 1;320xform.write[1] = 0;321xform.write[2] = 0;322xform.write[3] = 1;323return xform;324}325case RS::GLOBAL_VAR_TYPE_MAT3: {326return Basis();327}328case RS::GLOBAL_VAR_TYPE_TRANSFORM_2D: {329return Transform2D();330}331case RS::GLOBAL_VAR_TYPE_TRANSFORM: {332return Transform3D();333}334case RS::GLOBAL_VAR_TYPE_MAT4: {335return Projection();336}337case RS::GLOBAL_VAR_TYPE_SAMPLER2D: {338return "";339}340case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: {341return "";342}343case RS::GLOBAL_VAR_TYPE_SAMPLER3D: {344return "";345}346case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: {347return "";348}349case RS::GLOBAL_VAR_TYPE_SAMPLEREXT: {350return "";351}352default: {353return Variant();354}355}356}357358String ShaderGlobalsEditor::_check_new_variable_name(const String &p_variable_name) {359if (p_variable_name.is_empty()) {360return TTRC("Name cannot be empty.");361}362363if (!p_variable_name.is_valid_ascii_identifier()) {364return TTRC("Name must be a valid identifier.");365}366367return "";368}369370LineEdit *ShaderGlobalsEditor::get_name_box() const {371return variable_name;372}373374void ShaderGlobalsEditor::_variable_name_text_changed(const String &p_variable_name) {375const String &warning = _check_new_variable_name(p_variable_name.strip_edges());376variable_add->set_tooltip_text(warning);377variable_add->set_disabled(!warning.is_empty());378}379380void ShaderGlobalsEditor::_variable_added() {381String var = variable_name->get_text().strip_edges();382383if (RenderingServer::get_singleton()->global_shader_parameter_get(var).get_type() != Variant::NIL) {384EditorNode::get_singleton()->show_warning(vformat(TTR("Global shader parameter '%s' already exists."), var));385return;386}387388List<String> keywords;389ShaderLanguage::get_keyword_list(&keywords);390391if (keywords.find(var) != nullptr || var == "script") {392EditorNode::get_singleton()->show_warning(vformat(TTR("Name '%s' is a reserved shader language keyword."), var));393return;394}395396EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();397398Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected()));399400undo_redo->create_action(TTR("Add Shader Global Parameter"));401undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_add", var, RS::GlobalShaderParameterType(variable_type->get_selected()), value);402undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_remove", var);403Dictionary gv;404gv["type"] = global_var_type_names[variable_type->get_selected()];405gv["value"] = value;406407undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + var, gv);408undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + var, Variant());409undo_redo->add_do_method(this, "_changed");410undo_redo->add_undo_method(this, "_changed");411undo_redo->commit_action();412413variable_name->clear();414}415416void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {417EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();418419undo_redo->create_action(TTR("Add Shader Global Parameter"));420undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable);421undo_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));422423undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, Variant());424undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, GLOBAL_GET("shader_globals/" + p_variable));425undo_redo->add_do_method(this, "_changed");426undo_redo->add_undo_method(this, "_changed");427undo_redo->commit_action();428}429430void ShaderGlobalsEditor::_changed() {431emit_signal(SNAME("globals_changed"));432if (!interface->block_update) {433interface->notify_property_list_changed();434}435}436437void ShaderGlobalsEditor::_bind_methods() {438ClassDB::bind_method("_changed", &ShaderGlobalsEditor::_changed);439ADD_SIGNAL(MethodInfo("globals_changed"));440}441442void ShaderGlobalsEditor::_notification(int p_what) {443switch (p_what) {444case NOTIFICATION_VISIBILITY_CHANGED: {445if (is_visible_in_tree()) {446inspector->edit(interface);447}448} break;449450case NOTIFICATION_THEME_CHANGED: {451variable_add->set_button_icon(get_editor_theme_icon(SNAME("Add")));452} break;453454case NOTIFICATION_PREDELETE: {455inspector->edit(nullptr);456} break;457}458}459460ShaderGlobalsEditor::ShaderGlobalsEditor() {461ProjectSettings::get_singleton()->add_hidden_prefix("shader_globals/");462463HBoxContainer *add_menu_hb = memnew(HBoxContainer);464add_child(add_menu_hb);465466add_menu_hb->add_child(memnew(Label(TTRC("Name:"))));467variable_name = memnew(LineEdit);468variable_name->set_h_size_flags(SIZE_EXPAND_FILL);469variable_name->set_clear_button_enabled(true);470variable_name->connect(SceneStringName(text_changed), callable_mp(this, &ShaderGlobalsEditor::_variable_name_text_changed));471variable_name->connect(SceneStringName(text_submitted), callable_mp(this, &ShaderGlobalsEditor::_variable_added).unbind(1));472473add_menu_hb->add_child(variable_name);474475add_menu_hb->add_child(memnew(Label(TTRC("Type:"))));476variable_type = memnew(OptionButton);477variable_type->set_h_size_flags(SIZE_EXPAND_FILL);478add_menu_hb->add_child(variable_type);479480for (int i = 0; i < RS::GLOBAL_VAR_TYPE_MAX; i++) {481variable_type->add_item(global_var_type_names[i]);482}483484variable_add = memnew(Button(TTRC("Add")));485variable_add->set_disabled(true);486add_menu_hb->add_child(variable_add);487variable_add->connect(SceneStringName(pressed), callable_mp(this, &ShaderGlobalsEditor::_variable_added));488489inspector = memnew(EditorInspector);490inspector->set_v_size_flags(SIZE_EXPAND_FILL);491add_child(inspector);492inspector->set_use_wide_editors(true);493inspector->set_property_name_style(EditorPropertyNameProcessor::STYLE_RAW);494inspector->set_use_deletable_properties(true);495inspector->connect("property_deleted", callable_mp(this, &ShaderGlobalsEditor::_variable_deleted), CONNECT_DEFERRED);496497interface = memnew(ShaderGlobalsEditorInterface);498interface->connect("var_changed", callable_mp(this, &ShaderGlobalsEditor::_changed));499}500501ShaderGlobalsEditor::~ShaderGlobalsEditor() {502memdelete(interface);503}504505506