summaryrefslogtreecommitdiff
path: root/scene/resources/visual_shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/visual_shader.cpp')
-rw-r--r--scene/resources/visual_shader.cpp241
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);
}