diff options
Diffstat (limited to 'scene/resources/visual_shader.cpp')
-rw-r--r-- | scene/resources/visual_shader.cpp | 241 |
1 files changed, 233 insertions, 8 deletions
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 8475a34818..f5ea6adc85 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -117,6 +117,12 @@ void VisualShaderNode::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values"); ADD_SIGNAL(MethodInfo("editor_refresh_request")); + + BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR); + BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR); + BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN); + BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM); + BIND_ENUM_CONSTANT(PORT_TYPE_ICON_COLOR); } VisualShaderNode::VisualShaderNode() { @@ -125,6 +131,147 @@ VisualShaderNode::VisualShaderNode() { ///////////////////////////////////////////////////////// +void VisualShaderNodeCustom::update_ports() { + ERR_FAIL_COND(!get_script_instance()); + + input_ports.clear(); + if (get_script_instance()->has_method("_get_input_port_count")) { + int input_port_count = (int)get_script_instance()->call("_get_input_port_count"); + bool has_name = get_script_instance()->has_method("_get_input_port_name"); + bool has_type = get_script_instance()->has_method("_get_input_port_type"); + for (int i = 0; i < input_port_count; i++) { + Port port; + if (has_name) { + port.name = (String)get_script_instance()->call("_get_input_port_name", i); + } else { + port.name = "in" + itos(i); + } + if (has_type) { + port.type = (int)get_script_instance()->call("_get_input_port_type", i); + } else { + port.type = (int)PortType::PORT_TYPE_SCALAR; + } + input_ports.push_back(port); + } + } + output_ports.clear(); + if (get_script_instance()->has_method("_get_output_port_count")) { + int output_port_count = (int)get_script_instance()->call("_get_output_port_count"); + bool has_name = get_script_instance()->has_method("_get_output_port_name"); + bool has_type = get_script_instance()->has_method("_get_output_port_type"); + for (int i = 0; i < output_port_count; i++) { + Port port; + if (has_name) { + port.name = (String)get_script_instance()->call("_get_output_port_name", i); + } else { + port.name = "out" + itos(i); + } + if (has_type) { + port.type = (int)get_script_instance()->call("_get_output_port_type", i); + } else { + port.type = (int)PortType::PORT_TYPE_SCALAR; + } + output_ports.push_back(port); + } + } +} + +String VisualShaderNodeCustom::get_caption() const { + ERR_FAIL_COND_V(!get_script_instance(), ""); + if (get_script_instance()->has_method("_get_name")) { + return (String)get_script_instance()->call("_get_name"); + } + return "Unnamed"; +} + +int VisualShaderNodeCustom::get_input_port_count() const { + return input_ports.size(); +} + +VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_input_port_type(int p_port) const { + ERR_FAIL_INDEX_V(p_port, input_ports.size(), PORT_TYPE_SCALAR); + return (PortType)input_ports[p_port].type; +} + +String VisualShaderNodeCustom::get_input_port_name(int p_port) const { + ERR_FAIL_INDEX_V(p_port, input_ports.size(), ""); + return input_ports[p_port].name; +} + +int VisualShaderNodeCustom::get_output_port_count() const { + return output_ports.size(); +} + +VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_output_port_type(int p_port) const { + ERR_FAIL_INDEX_V(p_port, output_ports.size(), PORT_TYPE_SCALAR); + return (PortType)output_ports[p_port].type; +} + +String VisualShaderNodeCustom::get_output_port_name(int p_port) const { + ERR_FAIL_INDEX_V(p_port, output_ports.size(), ""); + return output_ports[p_port].name; +} + +String VisualShaderNodeCustom::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) const { + + ERR_FAIL_COND_V(!get_script_instance(), ""); + ERR_FAIL_COND_V(!get_script_instance()->has_method("_get_code"), ""); + Array input_vars; + for (int i = 0; i < get_input_port_count(); i++) { + input_vars.push_back(p_input_vars[i]); + } + Array output_vars; + for (int i = 0; i < get_output_port_count(); i++) { + output_vars.push_back(p_output_vars[i]); + } + String code = "\t{\n"; + String _code = (String)get_script_instance()->call("_get_code", input_vars, output_vars, (int)p_mode, (int)p_type); + bool nend = _code.ends_with("\n"); + _code = _code.insert(0, "\t\t"); + _code = _code.replace("\n", "\n\t\t"); + code += _code; + if (!nend) { + code += "\n\t}"; + } else { + code.remove(code.size() - 1); + code += "}"; + } + return code; +} + +String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + ERR_FAIL_COND_V(!get_script_instance(), ""); + if (get_script_instance()->has_method("_get_global_code")) { + String code = "// " + get_caption() + "\n"; + code += (String)get_script_instance()->call("_get_global_code", (int)p_mode); + code += "\n"; + return code; + } + return ""; +} + +void VisualShaderNodeCustom::_bind_methods() { + + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_name")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_description")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_category")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_subcategory")); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_return_icon_type")); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_count")); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_type", PropertyInfo(Variant::INT, "port"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_input_port_name", PropertyInfo(Variant::INT, "port"))); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_count")); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_type", PropertyInfo(Variant::INT, "port"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_output_port_name", PropertyInfo(Variant::INT, "port"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_code", PropertyInfo(Variant::ARRAY, "input_vars"), PropertyInfo(Variant::ARRAY, "output_vars"), PropertyInfo(Variant::INT, "mode"), PropertyInfo(Variant::INT, "type"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_global_code", PropertyInfo(Variant::INT, "mode"))); +} + +VisualShaderNodeCustom::VisualShaderNodeCustom() { +} + +///////////////////////////////////////////////////////// + void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) { ERR_FAIL_COND(p_node.is_null()); ERR_FAIL_COND(p_id < 2); @@ -150,6 +297,11 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co n.node->connect("changed", this, "_queue_update"); + Ref<VisualShaderNodeCustom> custom = n.node; + if (custom.is_valid()) { + custom->update_ports(); + } + g->nodes[p_id] = n; _queue_update(); @@ -307,11 +459,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, VisualShaderNode::PortType from_port_type = g->nodes[p_from_node].node->get_output_port_type(p_from_port); VisualShaderNode::PortType to_port_type = g->nodes[p_to_node].node->get_input_port_type(p_to_port); - if (!is_port_types_compatible(from_port_type, to_port_type)) { - ERR_EXPLAIN("Incompatible port types (scalar/vec/bool) with transform"); - ERR_FAIL_V(ERR_INVALID_PARAMETER); - return ERR_INVALID_PARAMETER; - } + ERR_FAIL_COND_V_MSG(!is_port_types_compatible(from_port_type, to_port_type), ERR_INVALID_PARAMETER, "Incompatible port types (scalar/vec/bool) with transform."); for (List<Connection>::Element *E = g->connections.front(); E; E = E->next()) { @@ -464,6 +612,25 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port global_code += String() + "shader_type canvas_item;\n"; + String global_expressions; + for (int i = 0, index = 0; i < TYPE_MAX; i++) { + for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) { + Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr()); + if (global_expression.is_valid()) { + + String expr = ""; + expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n"; + expr += global_expression->generate_global(get_mode(), Type(i), -1); + expr = expr.replace("\n", "\n\t"); + expr += "\n"; + global_expressions += expr; + } + } + } + + global_code += "\n"; + global_code += global_expressions; + //make it faster to go around through shader VMap<ConnectionKey, const List<Connection>::Element *> input_connections; VMap<ConnectionKey, const List<Connection>::Element *> output_connections; @@ -916,7 +1083,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } else if (defval.get_type() == Variant::BOOL) { bool val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - code += "\nbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; + code += "\tbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; } else if (defval.get_type() == Variant::VECTOR3) { Vector3 val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); @@ -969,6 +1136,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui bool skip_global = input.is_valid() && for_preview; if (!skip_global) { + global_code += vsnode->generate_global(get_mode(), type, node); if (!r_classes.has(vsnode->get_class_name())) { @@ -980,7 +1148,6 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } } - //handle normally code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); code += "\n"; // @@ -1057,6 +1224,22 @@ void VisualShader::_update_shader() const { static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" }; + String global_expressions; + for (int i = 0, index = 0; i < TYPE_MAX; i++) { + for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) { + Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr()); + if (global_expression.is_valid()) { + + String expr = ""; + expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n"; + expr += global_expression->generate_global(get_mode(), Type(i), -1); + expr = expr.replace("\n", "\n\t"); + expr += "\n"; + global_expressions += expr; + } + } + } + for (int i = 0; i < TYPE_MAX; i++) { //make it faster to go around through shader @@ -1091,6 +1274,7 @@ void VisualShader::_update_shader() const { global_code += "\n\n"; String final_code = global_code; final_code += global_code_per_node; + final_code += global_expressions; String tcode = code; for (int i = 0; i < TYPE_MAX; i++) { tcode = tcode.insert(insertion_pos[i], global_code_per_func[Type(i)]); @@ -1101,6 +1285,10 @@ void VisualShader::_update_shader() const { for (int i = 0; i < default_tex_params.size(); i++) { const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param); } + if (previous_code != final_code) { + const_cast<VisualShader *>(this)->emit_signal("changed"); + } + previous_code = final_code; } void VisualShader::_queue_update() { @@ -1211,6 +1399,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, // Spatial, Fragment { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, @@ -1235,6 +1424,8 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "front_facing", "FRONT_FACING" }, // Spatial, Light { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, @@ -1256,6 +1447,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, // Canvas Item, Vertex { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX,0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" }, @@ -2185,6 +2377,14 @@ void VisualShaderNodeGroupBase::_apply_port_changes() { } } +void VisualShaderNodeGroupBase::set_editable(bool p_enabled) { + editable = p_enabled; +} + +bool VisualShaderNodeGroupBase::is_editable() const { + return editable; +} + void VisualShaderNodeGroupBase::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size); @@ -2220,6 +2420,11 @@ void VisualShaderNodeGroupBase::_bind_methods() { ClassDB::bind_method(D_METHOD("set_control", "control", "index"), &VisualShaderNodeGroupBase::set_control); ClassDB::bind_method(D_METHOD("get_control", "index"), &VisualShaderNodeGroupBase::get_control); + + ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &VisualShaderNodeGroupBase::set_editable); + ClassDB::bind_method(D_METHOD("is_editable"), &VisualShaderNodeGroupBase::is_editable); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); } String VisualShaderNodeGroupBase::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) const { @@ -2230,6 +2435,7 @@ VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() { size = Size2(0, 0); inputs = ""; outputs = ""; + editable = false; } ////////////// Expression @@ -2260,8 +2466,11 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad static Vector<String> pre_symbols; if (pre_symbols.empty()) { pre_symbols.push_back("\t"); + pre_symbols.push_back(","); + pre_symbols.push_back(";"); pre_symbols.push_back("{"); pre_symbols.push_back("["); + pre_symbols.push_back("]"); pre_symbols.push_back("("); pre_symbols.push_back(" "); pre_symbols.push_back("-"); @@ -2276,11 +2485,12 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad static Vector<String> post_symbols; if (post_symbols.empty()) { - post_symbols.push_back("\0"); post_symbols.push_back("\t"); post_symbols.push_back("\n"); + post_symbols.push_back(","); post_symbols.push_back(";"); post_symbols.push_back("}"); + post_symbols.push_back("["); post_symbols.push_back("]"); post_symbols.push_back(")"); post_symbols.push_back(" "); @@ -2355,4 +2565,19 @@ void VisualShaderNodeExpression::_bind_methods() { VisualShaderNodeExpression::VisualShaderNodeExpression() { expression = ""; + set_editable(true); +} + +////////////// Global Expression + +String VisualShaderNodeGlobalExpression::get_caption() const { + return "GlobalExpression"; +} + +String VisualShaderNodeGlobalExpression::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return expression; +} + +VisualShaderNodeGlobalExpression::VisualShaderNodeGlobalExpression() { + set_editable(false); } |