diff options
| -rw-r--r-- | editor/plugins/visual_shader_editor_plugin.cpp | 202 | ||||
| -rw-r--r-- | editor/plugins/visual_shader_editor_plugin.h | 4 | ||||
| -rw-r--r-- | scene/resources/visual_shader.cpp | 147 | ||||
| -rw-r--r-- | scene/resources/visual_shader.h | 8 | ||||
| -rw-r--r-- | scene/resources/visual_shader_nodes.cpp | 28 | ||||
| -rw-r--r-- | scene/resources/visual_shader_nodes.h | 4 | 
6 files changed, 363 insertions, 30 deletions
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 8be55296d9..6fd61d2e00 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -322,6 +322,12 @@ void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_u  	links[p_node_id].uniform_name = p_uniform_name;  } +void VisualShaderGraphPlugin::update_theme() { +	vector_expanded_color[0] = VisualShaderEditor::get_singleton()->get_theme_color("axis_x_color", "Editor"); // red +	vector_expanded_color[1] = VisualShaderEditor::get_singleton()->get_theme_color("axis_y_color", "Editor"); // green +	vector_expanded_color[2] = VisualShaderEditor::get_singleton()->get_theme_color("axis_z_color", "Editor"); // blue +} +  void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {  	if (p_type != visual_shader->get_shader_type()) {  		return; @@ -340,6 +346,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {  		Color(1.0, 1.0, 0.0), // sampler  	}; +	static const String vector_expanded_name[3] = { +		"red", +		"green", +		"blue" +	}; +  	Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);  	Ref<VisualShaderNodeResizableBase> resizable_node = Object::cast_to<VisualShaderNodeResizableBase>(vsnode.ptr()); @@ -553,13 +565,32 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {  		}  	} -	for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) { +	int output_port_count = 0; +	for (int i = 0; i < vsnode->get_output_port_count(); i++) { +		if (vsnode->_is_output_port_expanded(i)) { +			if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { +				output_port_count += 3; +			} +		} +		output_port_count++; +	} +	int max_ports = MAX(vsnode->get_input_port_count(), output_port_count); +	VisualShaderNode::PortType expanded_type = VisualShaderNode::PORT_TYPE_SCALAR; +	int expanded_port_counter = 0; + +	for (int i = 0, j = 0; i < max_ports; i++, j++) { +		if (expanded_type == VisualShaderNode::PORT_TYPE_VECTOR && expanded_port_counter >= 3) { +			expanded_type = VisualShaderNode::PORT_TYPE_SCALAR; +			expanded_port_counter = 0; +			i -= 3; +		} +  		if (vsnode->is_port_separator(i)) {  			node->add_child(memnew(HSeparator));  			port_offset++;  		} -		bool valid_left = i < vsnode->get_input_port_count(); +		bool valid_left = j < vsnode->get_input_port_count();  		VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR;  		bool port_left_used = false;  		String name_left; @@ -567,18 +598,24 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {  			name_left = vsnode->get_input_port_name(i);  			port_left = vsnode->get_input_port_type(i);  			for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { -				if (E->get().to_node == p_id && E->get().to_port == i) { +				if (E->get().to_node == p_id && E->get().to_port == j) {  					port_left_used = true;  				}  			}  		} -		bool valid_right = i < vsnode->get_output_port_count(); +		bool valid_right = true;  		VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR;  		String name_right; -		if (valid_right) { -			name_right = vsnode->get_output_port_name(i); -			port_right = vsnode->get_output_port_type(i); + +		if (expanded_type == VisualShaderNode::PORT_TYPE_SCALAR) { +			valid_right = i < vsnode->get_output_port_count(); +			if (valid_right) { +				name_right = vsnode->get_output_port_name(i); +				port_right = vsnode->get_output_port_type(i); +			} +		} else { +			name_right = vector_expanded_name[expanded_port_counter++];  		}  		HBoxContainer *hb = memnew(HBoxContainer); @@ -686,17 +723,29 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {  			}  		} -		if (valid_right && visual_shader->get_shader_type() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) { -			TextureButton *preview = memnew(TextureButton); -			preview->set_toggle_mode(true); -			preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons")); -			preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityVisible", "EditorIcons")); -			preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER); +		if (valid_right) { +			if (vsnode->is_output_port_expandable(i)) { +				TextureButton *expand = memnew(TextureButton); +				expand->set_toggle_mode(true); +				expand->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiTreeArrowDown", "EditorIcons")); +				expand->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiTreeArrowRight", "EditorIcons")); +				expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER); +				expand->set_pressed(vsnode->_is_output_port_expanded(i)); +				expand->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_expand_output_port), varray(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED); +				hb->add_child(expand); +			} +			if (visual_shader->get_shader_type() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) { +				TextureButton *preview = memnew(TextureButton); +				preview->set_toggle_mode(true); +				preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons")); +				preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityVisible", "EditorIcons")); +				preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER); -			register_output_port(p_id, i, preview); +				register_output_port(p_id, j, preview); -			preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, i), CONNECT_DEFERRED); -			hb->add_child(preview); +				preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, j), CONNECT_DEFERRED); +				hb->add_child(preview); +			}  		}  		if (is_group) { @@ -708,7 +757,40 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {  		node->add_child(hb); +		if (expanded_type != VisualShaderNode::PORT_TYPE_SCALAR) { +			continue; +		} +  		node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]); + +		if (vsnode->_is_output_port_expanded(i)) { +			if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { +				port_offset++; +				valid_left = (i + 1) < vsnode->get_input_port_count(); +				port_left = VisualShaderNode::PORT_TYPE_SCALAR; +				if (valid_left) { +					port_left = vsnode->get_input_port_type(i + 1); +				} +				node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]); +				port_offset++; + +				valid_left = (i + 2) < vsnode->get_input_port_count(); +				port_left = VisualShaderNode::PORT_TYPE_SCALAR; +				if (valid_left) { +					port_left = vsnode->get_input_port_type(i + 2); +				} +				node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]); +				port_offset++; + +				valid_left = (i + 3) < vsnode->get_input_port_count(); +				port_left = VisualShaderNode::PORT_TYPE_SCALAR; +				if (valid_left) { +					port_left = vsnode->get_input_port_type(i + 3); +				} +				node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]); +				expanded_type = VisualShaderNode::PORT_TYPE_VECTOR; +			} +		}  	}  	if (vsnode->get_output_port_for_preview() >= 0) { @@ -1293,6 +1375,7 @@ void VisualShaderEditor::_update_graph() {  	graph_plugin->clear_links();  	graph_plugin->make_dirty(true); +	graph_plugin->update_theme();  	for (int n_i = 0; n_i < nodes.size(); n_i++) {  		graph_plugin->add_node(type, nodes[n_i]); @@ -1441,6 +1524,92 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *  	undo_redo->commit_action();  } +void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expand) { +	VisualShader::Type type = get_current_shader_type(); + +	Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node); +	ERR_FAIL_COND(!node.is_valid()); + +	if (p_expand) { +		undo_redo->create_action(TTR("Expand Output Port")); +	} else { +		undo_redo->create_action(TTR("Shrink Output Port")); +	} + +	undo_redo->add_do_method(node.ptr(), "_set_output_port_expanded", p_port, p_expand); +	undo_redo->add_undo_method(node.ptr(), "_set_output_port_expanded", p_port, !p_expand); + +	int type_size = 0; +	if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_VECTOR) { +		type_size = 3; +	} + +	List<VisualShader::Connection> conns; +	visual_shader->get_node_connections(type, &conns); + +	for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { +		int from_node = E->get().from_node; +		int from_port = E->get().from_port; +		int to_node = E->get().to_node; +		int to_port = E->get().to_port; + +		if (from_node == p_node) { +			if (p_expand) { +				if (from_port > p_port) { // reconnect ports after expanded ports +					undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); +					undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + +					undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); +					undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); + +					undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port + type_size, to_node, to_port); +					undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port); + +					undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port + type_size, to_node, to_port); +					undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port); +				} +			} else { +				if (from_port > p_port + type_size) { // reconnect ports after expanded ports +					undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); +					undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + +					undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); +					undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); + +					undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port); +					undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port); + +					undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port); +					undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port); +				} else if (from_port > p_port) { // disconnect component ports +					undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); +					undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + +					undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); +					undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); +				} +			} +		} +	} + +	int preview_port = node->get_output_port_for_preview(); +	if (p_expand) { +		if (preview_port > p_port) { +			undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port + type_size); +			undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port); +		} +	} else { +		if (preview_port > p_port + type_size) { +			undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - type_size); +			undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port); +		} +	} + +	undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); +	undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); +	undo_redo->commit_action(); +} +  void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {  	VisualShader::Type type = get_current_shader_type();  	Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); @@ -3469,6 +3638,7 @@ void VisualShaderEditor::_bind_methods() {  	ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected);  	ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);  	ClassDB::bind_method("_update_uniform", &VisualShaderEditor::_update_uniform); +	ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);  	ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);  	ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 2f438cc6c8..b3510aafa1 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -83,6 +83,8 @@ private:  	List<VisualShader::Connection> connections;  	bool dirty = false; +	Color vector_expanded_color[3]; +  protected:  	static void _bind_methods(); @@ -119,6 +121,7 @@ public:  	void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression);  	int get_constant_index(float p_constant) const;  	void update_node_size(int p_node_id); +	void update_theme();  	VisualShader::Type get_shader_type() const;  	VisualShaderGraphPlugin(); @@ -401,6 +404,7 @@ class VisualShaderEditor : public VBoxContainer {  	void _remove_output_port(int p_node, int p_port);  	void _change_output_port_type(int p_type, int p_node, int p_port);  	void _change_output_port_name(const String &p_text, Object *p_line_edit, int p_node, int p_port); +	void _expand_output_port(int p_node, int p_port, bool p_expand);  	void _expression_focus_out(Object *code_edit, int p_node); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index da29f2ebd8..5ac1ad935e 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -94,6 +94,52 @@ bool VisualShaderNode::is_generate_input_var(int p_port) const {  	return true;  } +bool VisualShaderNode::is_output_port_expandable(int p_port) const { +	return false; +} + +void VisualShaderNode::_set_output_ports_expanded(const Array &p_values) { +	for (int i = 0; i < p_values.size(); i++) { +		expanded_output_ports[p_values[i]] = true; +	} +	emit_changed(); +} + +Array VisualShaderNode::_get_output_ports_expanded() const { +	Array arr; +	for (int i = 0; i < get_output_port_count(); i++) { +		if (_is_output_port_expanded(i)) { +			arr.push_back(i); +		} +	} +	return arr; +} + +void VisualShaderNode::_set_output_port_expanded(int p_port, bool p_expanded) { +	expanded_output_ports[p_port] = p_expanded; +	emit_changed(); +} + +bool VisualShaderNode::_is_output_port_expanded(int p_port) const { +	if (expanded_output_ports.has(p_port)) { +		return expanded_output_ports[p_port]; +	} +	return false; +} + +int VisualShaderNode::get_expanded_output_port_count() const { +	int count = get_output_port_count(); +	int count2 = count; +	for (int i = 0; i < count; i++) { +		if (is_output_port_expandable(i) && _is_output_port_expanded(i)) { +			if (get_output_port_type(i) == PORT_TYPE_VECTOR) { +				count2 += 3; +			} +		} +	} +	return count2; +} +  bool VisualShaderNode::is_code_generated() const {  	return true;  } @@ -157,6 +203,12 @@ void VisualShaderNode::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview);  	ClassDB::bind_method(D_METHOD("get_output_port_for_preview"), &VisualShaderNode::get_output_port_for_preview); +	ClassDB::bind_method(D_METHOD("_set_output_port_expanded", "port"), &VisualShaderNode::_set_output_port_expanded); +	ClassDB::bind_method(D_METHOD("_is_output_port_expanded"), &VisualShaderNode::_is_output_port_expanded); + +	ClassDB::bind_method(D_METHOD("_set_output_ports_expanded", "values"), &VisualShaderNode::_set_output_ports_expanded); +	ClassDB::bind_method(D_METHOD("_get_output_ports_expanded"), &VisualShaderNode::_get_output_ports_expanded); +  	ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value"), &VisualShaderNode::set_input_port_default_value);  	ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value); @@ -165,6 +217,7 @@ 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 | PROPERTY_USAGE_INTERNAL), "set_default_input_values", "get_default_input_values"); +	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "expanded_output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_output_ports_expanded", "_get_output_ports_expanded");  	ADD_SIGNAL(MethodInfo("editor_refresh_request"));  	BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR); @@ -576,7 +629,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po  		return false;  	} -	if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_output_port_count()) { +	if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_expanded_output_port_count()) {  		return false;  	} @@ -617,7 +670,7 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from  	Graph *g = &graph[p_type];  	ERR_FAIL_COND(!g->nodes.has(p_from_node)); -	ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_output_port_count()); +	ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count());  	ERR_FAIL_COND(!g->nodes.has(p_to_node));  	ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count()); @@ -639,7 +692,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,  	Graph *g = &graph[p_type];  	ERR_FAIL_COND_V(!g->nodes.has(p_from_node), ERR_INVALID_PARAMETER); -	ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_output_port_count(), ERR_INVALID_PARAMETER); +	ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count(), ERR_INVALID_PARAMETER);  	ERR_FAIL_COND_V(!g->nodes.has(p_to_node), ERR_INVALID_PARAMETER);  	ERR_FAIL_INDEX_V(p_to_port, g->nodes[p_to_node].node->get_input_port_count(), ERR_INVALID_PARAMETER); @@ -790,7 +843,7 @@ bool VisualShader::is_text_shader() const {  String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &default_tex_params) const {  	Ref<VisualShaderNode> node = get_node(p_type, p_node);  	ERR_FAIL_COND_V(!node.is_valid(), String()); -	ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_output_port_count(), String()); +	ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_expanded_output_port_count(), String());  	ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String());  	StringBuilder global_code; @@ -1362,13 +1415,30 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui  	}  	int output_count = vsnode->get_output_port_count(); +	int initial_output_count = output_count; + +	Map<int, bool> expanded_output_ports; + +	for (int i = 0; i < initial_output_count; i++) { +		bool expanded = false; + +		if (vsnode->is_output_port_expandable(i) && vsnode->_is_output_port_expanded(i)) { +			expanded = true; + +			if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { +				output_count += 3; +			} +		} +		expanded_output_ports.insert(i, expanded); +	} +  	Vector<String> output_vars; -	output_vars.resize(vsnode->get_output_port_count()); +	output_vars.resize(output_count);  	String *outputs = output_vars.ptrw();  	if (vsnode->is_simple_decl()) { // less code to generate for some simple_decl nodes -		for (int i = 0; i < output_count; i++) { -			String var_name = "n_out" + itos(node) + "p" + itos(i); +		for (int i = 0, j = 0; i < initial_output_count; i++, j++) { +			String var_name = "n_out" + itos(node) + "p" + itos(j);  			switch (vsnode->get_output_port_type(i)) {  				case VisualShaderNode::PORT_TYPE_SCALAR:  					outputs[i] = "float " + var_name; @@ -1388,35 +1458,84 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui  				default: {  				}  			} +			if (expanded_output_ports[i]) { +				if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { +					j += 3; +				} +			}  		}  	} else { -		for (int i = 0; i < output_count; i++) { -			outputs[i] = "n_out" + itos(node) + "p" + itos(i); +		for (int i = 0, j = 0; i < initial_output_count; i++, j++) { +			outputs[i] = "n_out" + itos(node) + "p" + itos(j);  			switch (vsnode->get_output_port_type(i)) {  				case VisualShaderNode::PORT_TYPE_SCALAR: -					code += String() + "\tfloat " + outputs[i] + ";\n"; +					code += "\tfloat " + outputs[i] + ";\n";  					break;  				case VisualShaderNode::PORT_TYPE_SCALAR_INT: -					code += String() + "\tint " + outputs[i] + ";\n"; +					code += "\tint " + outputs[i] + ";\n";  					break;  				case VisualShaderNode::PORT_TYPE_VECTOR: -					code += String() + "\tvec3 " + outputs[i] + ";\n"; +					code += "\tvec3 " + outputs[i] + ";\n";  					break;  				case VisualShaderNode::PORT_TYPE_BOOLEAN: -					code += String() + "\tbool " + outputs[i] + ";\n"; +					code += "\tbool " + outputs[i] + ";\n";  					break;  				case VisualShaderNode::PORT_TYPE_TRANSFORM: -					code += String() + "\tmat4 " + outputs[i] + ";\n"; +					code += "\tmat4 " + outputs[i] + ";\n";  					break;  				default: {  				}  			} +			if (expanded_output_ports[i]) { +				if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { +					j += 3; +				} +			}  		}  	}  	code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); +	for (int i = 0; i < output_count; i++) { +		bool new_line_inserted = false; +		if (expanded_output_ports[i]) { +			if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { +				if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component +					if (!new_line_inserted) { +						code += "\n"; +						new_line_inserted = true; +					} +					String r = "n_out" + itos(node) + "p" + itos(i + 1); +					code += "\tfloat " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n"; +					outputs[i + 1] = r; +				} + +				if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component +					if (!new_line_inserted) { +						code += "\n"; +						new_line_inserted = true; +					} +					String g = "n_out" + itos(node) + "p" + itos(i + 2); +					code += "\tfloat " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n"; +					outputs[i + 2] = g; +				} + +				if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component +					if (!new_line_inserted) { +						code += "\n"; +						new_line_inserted = true; +					} +					String b = "n_out" + itos(node) + "p" + itos(i + 3); +					code += "\tfloat " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n"; +					outputs[i + 3] = b; +				} + +				i += 3; +			} +		} +	} +  	code += "\n"; //  	processed.insert(node); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 841672294e..cc9a867e64 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -199,6 +199,7 @@ class VisualShaderNode : public Resource {  	Map<int, Variant> default_input_values;  	Map<int, bool> connected_input_ports;  	Map<int, int> connected_output_ports; +	Map<int, bool> expanded_output_ports;  protected:  	bool simple_decl = true; @@ -245,6 +246,13 @@ public:  	void set_input_port_connected(int p_port, bool p_connected);  	virtual bool is_generate_input_var(int p_port) const; +	virtual bool is_output_port_expandable(int p_port) const; +	void _set_output_ports_expanded(const Array &p_data); +	Array _get_output_ports_expanded() const; +	void _set_output_port_expanded(int p_port, bool p_expanded); +	bool _is_output_port_expanded(int p_port) const; +	int get_expanded_output_port_count() const; +  	virtual bool is_code_generated() const;  	virtual bool is_show_prop_names() const;  	virtual bool is_use_prop_slots() const; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index c2a6ad72d7..314333158c 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -242,6 +242,13 @@ String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const {  	return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port  } +bool VisualShaderNodeColorConstant::is_output_port_expandable(int p_port) const { +	if (p_port == 0) { +		return true; +	} +	return false; +} +  String VisualShaderNodeColorConstant::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 {  	String code;  	code += "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.r, constant.g, constant.b) + ";\n"; @@ -455,6 +462,13 @@ String VisualShaderNodeTexture::get_output_port_name(int p_port) const {  	return p_port == 0 ? "rgb" : "alpha";  } +bool VisualShaderNodeTexture::is_output_port_expandable(int p_port) const { +	if (p_port == 0) { +		return true; +	} +	return false; +} +  String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const {  	if (p_port == 0) {  		return "default"; @@ -917,6 +931,13 @@ String VisualShaderNodeSample3D::get_output_port_name(int p_port) const {  	return p_port == 0 ? "rgb" : "alpha";  } +bool VisualShaderNodeSample3D::is_output_port_expandable(int p_port) const { +	if (p_port == 0) { +		return true; +	} +	return false; +} +  String VisualShaderNodeSample3D::get_input_port_default_hint(int p_port) const {  	if (p_port == 0) {  		return "default"; @@ -1168,6 +1189,13 @@ String VisualShaderNodeCubemap::get_output_port_name(int p_port) const {  	return p_port == 0 ? "rgb" : "alpha";  } +bool VisualShaderNodeCubemap::is_output_port_expandable(int p_port) const { +	if (p_port == 0) { +		return true; +	} +	return false; +} +  Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCubemap::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {  	VisualShader::DefaultTextureParam dtp;  	dtp.name = make_unique_id(p_type, p_id, "cube"); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index d3397fad6f..50329d122d 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -163,6 +163,7 @@ public:  	virtual int get_output_port_count() const override;  	virtual PortType get_output_port_type(int p_port) const override;  	virtual String get_output_port_name(int p_port) const override; +	virtual bool is_output_port_expandable(int p_port) const override;  	virtual String 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 = false) const override; @@ -275,6 +276,7 @@ public:  	virtual int get_output_port_count() const override;  	virtual PortType get_output_port_type(int p_port) const override;  	virtual String get_output_port_name(int p_port) const override; +	virtual bool is_output_port_expandable(int p_port) const override;  	virtual String get_input_port_default_hint(int p_port) const override; @@ -359,6 +361,7 @@ public:  	virtual int get_output_port_count() const override;  	virtual PortType get_output_port_type(int p_port) const override;  	virtual String get_output_port_name(int p_port) const override; +	virtual bool is_output_port_expandable(int p_port) const override;  	virtual String 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 = false) const override; @@ -452,6 +455,7 @@ public:  	virtual int get_output_port_count() const override;  	virtual PortType get_output_port_type(int p_port) const override;  	virtual String get_output_port_name(int p_port) const override; +	virtual bool is_output_port_expandable(int p_port) const override;  	virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override;  	virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;  |