ソースを参照

Merge pull request #42558 from Chaosus/vs_curve

Added visual shader node to easy gather data from a CurveTexture
Rémi Verschelde 4 年 前
コミット
6b20859984

+ 17 - 0
doc/classes/VisualShaderNodeCurveTexture.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeCurveTexture" inherits="VisualShaderNodeResizableBase" version="4.0">
+	<brief_description>
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+	<methods>
+	</methods>
+	<members>
+		<member name="texture" type="CurveTexture" setter="set_texture" getter="get_texture">
+		</member>
+	</members>
+	<constants>
+	</constants>
+</class>

+ 1 - 6
doc/classes/VisualShaderNodeGroupBase.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeGroupBase" inherits="VisualShaderNode" version="4.0">
+<class name="VisualShaderNodeGroupBase" inherits="VisualShaderNodeResizableBase" version="4.0">
 	<brief_description>
 		Base class for a family of nodes with variable amount of input and output ports within the visual shader graph.
 	</brief_description>
@@ -199,11 +199,6 @@
 			</description>
 		</method>
 	</methods>
-	<members>
-		<member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 0, 0 )">
-			The size of the node in the visual shader graph.
-		</member>
-	</members>
 	<constants>
 	</constants>
 </class>

+ 18 - 0
doc/classes/VisualShaderNodeResizableBase.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeResizableBase" inherits="VisualShaderNode" version="4.0">
+	<brief_description>
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+	<methods>
+	</methods>
+	<members>
+		<member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 0, 0 )">
+			The size of the node in the visual shader graph.
+		</member>
+	</members>
+	<constants>
+	</constants>
+</class>

+ 89 - 13
editor/plugins/visual_shader_editor_plugin.cpp

@@ -108,6 +108,7 @@ void VisualShaderGraphPlugin::_bind_methods() {
 	ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);
 	ClassDB::bind_method("set_uniform_name", &VisualShaderGraphPlugin::set_uniform_name);
 	ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression);
+	ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve);
 	ClassDB::bind_method("update_constant", &VisualShaderGraphPlugin::update_constant);
 }
 
@@ -206,6 +207,14 @@ void VisualShaderGraphPlugin::set_uniform_name(VisualShader::Type p_type, int p_
 	}
 }
 
+void VisualShaderGraphPlugin::update_curve(int p_node_id) {
+	if (links.has(p_node_id) && links[p_node_id].curve_editor) {
+		if (((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture().is_valid()) {
+			links[p_node_id].curve_editor->set_curve(((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture()->get_curve());
+		}
+	}
+}
+
 int VisualShaderGraphPlugin::get_constant_index(float p_constant) const {
 	for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {
 		if (Math::is_equal_approx(p_constant, float_constant_defs[i].value)) {
@@ -253,6 +262,10 @@ void VisualShaderGraphPlugin::register_expression_edit(int p_node_id, CodeEdit *
 	links[p_node_id].expression_edit = p_expression_edit;
 }
 
+void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, CurveEditor *p_curve_editor) {
+	links[p_node_id].curve_editor = p_curve_editor;
+}
+
 void VisualShaderGraphPlugin::update_uniform_refs() {
 	for (Map<int, Link>::Element *E = links.front(); E; E = E->next()) {
 		VisualShaderNodeUniformRef *ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().visual_node);
@@ -296,7 +309,7 @@ void VisualShaderGraphPlugin::make_dirty(bool p_enabled) {
 }
 
 void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) {
-	links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr, nullptr, nullptr });
+	links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr, nullptr, nullptr, nullptr });
 }
 
 void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) {
@@ -327,9 +340,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 
 	Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id);
 
+	Ref<VisualShaderNodeResizableBase> resizable_node = Object::cast_to<VisualShaderNodeResizableBase>(vsnode.ptr());
+	bool is_resizable = !resizable_node.is_null();
+	Size2 size = Size2(0, 0);
+
 	Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(vsnode.ptr());
 	bool is_group = !group_node.is_null();
-	Size2 size = Size2(0, 0);
 
 	Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(group_node.ptr());
 	bool is_expression = !expression_node.is_null();
@@ -338,8 +354,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 	GraphNode *node = memnew(GraphNode);
 	register_link(p_type, p_id, vsnode.ptr(), node);
 
-	if (is_group) {
-		size = group_node->get_size();
+	if (is_resizable) {
+		size = resizable_node->get_size();
 
 		node->set_resizable(true);
 		node->connect("resize_request", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_node_resized), varray((int)p_type, p_id));
@@ -403,6 +419,18 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 		}
 	}
 
+	Ref<VisualShaderNodeCurveTexture> curve = vsnode;
+	if (curve.is_valid()) {
+		if (curve->get_texture().is_valid() && !curve->get_texture()->is_connected("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve))) {
+			curve->get_texture()->connect("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve), varray(p_id));
+		}
+
+		HBoxContainer *hbox = memnew(HBoxContainer);
+		custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+		hbox->add_child(custom_editor);
+		custom_editor = hbox;
+	}
+
 	Ref<VisualShaderNodeFloatConstant> float_const = vsnode;
 	if (float_const.is_valid()) {
 		HBoxContainer *hbox = memnew(HBoxContainer);
@@ -425,6 +453,37 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 	} else if (custom_editor) {
 		port_offset++;
 		node->add_child(custom_editor);
+
+		if (curve.is_valid()) {
+			VisualShaderEditor::get_singleton()->graph->add_child(node);
+			VisualShaderEditor::get_singleton()->_update_created_node(node);
+
+			CurveEditor *curve_editor = memnew(CurveEditor);
+			node->add_child(curve_editor);
+			register_curve_editor(p_id, curve_editor);
+			curve_editor->set_custom_minimum_size(Size2(300, 0));
+			curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+			if (curve->get_texture().is_valid()) {
+				curve_editor->set_curve(curve->get_texture()->get_curve());
+			}
+
+			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, 0, preview);
+
+			preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, 0), CONNECT_DEFERRED);
+			custom_editor->add_child(preview);
+
+			VisualShaderNode::PortType port_left = vsnode->get_input_port_type(0);
+			VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0);
+			node->set_slot(0, true, port_left, type_color[port_left], true, port_right, type_color[port_right]);
+
+			VisualShaderEditor::get_singleton()->call_deferred("_set_node_size", (int)p_type, p_id, size);
+		}
 		if (vsnode->is_use_prop_slots()) {
 			return;
 		}
@@ -672,7 +731,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 	if (!uniform.is_valid()) {
 		VisualShaderEditor::get_singleton()->graph->add_child(node);
 		VisualShaderEditor::get_singleton()->_update_created_node(node);
-		if (is_group) {
+		if (is_resizable) {
 			VisualShaderEditor::get_singleton()->call_deferred("_set_node_size", (int)p_type, p_id, size);
 		}
 	}
@@ -1425,17 +1484,17 @@ void VisualShaderEditor::_expression_focus_out(Object *code_edit, int p_node) {
 
 void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) {
 	VisualShader::Type type = VisualShader::Type(p_type);
-	Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);
+	Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(type, p_node);
 	if (node.is_null()) {
 		return;
 	}
 
-	Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
-	if (group_node.is_null()) {
-		return;
+	Size2 size = p_size;
+	if (!node->is_allow_v_resize()) {
+		size.y = 0;
 	}
 
-	group_node->set_size(p_size);
+	node->set_size(size);
 
 	if (get_current_shader_type() == type) {
 		Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
@@ -1454,11 +1513,11 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
 			return;
 		}
 
-		gn->set_custom_minimum_size(p_size);
+		gn->set_custom_minimum_size(size);
 		gn->set_size(Size2(1, 1));
 
 		if (!expression_node.is_null() && text_box) {
-			Size2 box_size = p_size;
+			Size2 box_size = size;
 			if (gn != nullptr) {
 				if (box_size.x < 150 * EDSCALE || box_size.y < 0) {
 					box_size.x = gn->get_size().x;
@@ -1475,7 +1534,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
 }
 
 void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, int p_node) {
-	Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(VisualShader::Type(p_type), p_node);
+	Ref<VisualShaderNodeResizableBase> node = visual_shader->get_node(VisualShader::Type(p_type), p_node);
 	if (node.is_null()) {
 		return;
 	}
@@ -1655,6 +1714,11 @@ void VisualShaderEditor::_add_texture3d_node(const String &p_path) {
 	texture3d->set_texture(ResourceLoader::load(p_path));
 }
 
+void VisualShaderEditor::_add_curve_node(const String &p_path) {
+	VisualShaderNodeCurveTexture *curve = (VisualShaderNodeCurveTexture *)_add_node(curve_node_option_idx, -1);
+	curve->set_texture(ResourceLoader::load(p_path));
+}
+
 VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
 	ERR_FAIL_INDEX_V(p_idx, add_options.size(), nullptr);
 
@@ -1833,6 +1897,11 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
 		undo_redo->add_undo_method(this, "_update_uniforms", true);
 	}
 
+	VisualShaderNodeCurveTexture *curve = Object::cast_to<VisualShaderNodeCurveTexture>(vsnode.ptr());
+	if (curve) {
+		graph_plugin->call_deferred("update_curve", id_to_use);
+	}
+
 	undo_redo->commit_action();
 	return vsnode.ptr();
 }
@@ -2676,6 +2745,11 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
 							_add_custom_node(arr[i]);
 							j++;
 						}
+					} else if (type == "CurveTexture") {
+						saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
+						saved_node_pos_dirty = true;
+						_add_curve_node(arr[i]);
+						j++;
 					} else if (ClassDB::get_parent_class(type) == "Texture2D") {
 						saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE);
 						saved_node_pos_dirty = true;
@@ -3301,6 +3375,8 @@ VisualShaderEditor::VisualShaderEditor() {
 	// TEXTURES
 	cubemap_node_option_idx = add_options.size();
 	add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), -1, -1));
+	curve_node_option_idx = add_options.size();
+	add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), -1, -1));
 	texture2d_node_option_idx = add_options.size();
 	add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), -1, -1));
 	texture2d_array_node_option_idx = add_options.size();

+ 7 - 0
editor/plugins/visual_shader_editor_plugin.h

@@ -33,6 +33,7 @@
 
 #include "editor/editor_node.h"
 #include "editor/editor_plugin.h"
+#include "editor/plugins/curve_editor_plugin.h"
 #include "editor/property_editor.h"
 #include "scene/gui/button.h"
 #include "scene/gui/graph_edit.h"
@@ -74,6 +75,7 @@ private:
 		LineEdit *uniform_name;
 		OptionButton *const_op;
 		CodeEdit *expression_edit;
+		CurveEditor *curve_editor;
 	};
 
 	Ref<VisualShader> visual_shader;
@@ -93,6 +95,7 @@ public:
 	void register_default_input_button(int p_node_id, int p_port_id, Button *p_button);
 	void register_constant_option_btn(int p_node_id, OptionButton *p_button);
 	void register_expression_edit(int p_node_id, CodeEdit *p_expression_edit);
+	void register_curve_editor(int p_node_id, CurveEditor *p_curve_editor);
 	void clear_links();
 	void set_shader_type(VisualShader::Type p_type);
 	bool is_preview_visible(int p_id) const;
@@ -111,6 +114,7 @@ public:
 	void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value);
 	void update_uniform_refs();
 	void set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name);
+	void update_curve(int p_node_id);
 	void update_constant(VisualShader::Type p_type, int p_node_id);
 	void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression);
 	int get_constant_index(float p_constant) const;
@@ -254,6 +258,7 @@ class VisualShaderEditor : public VBoxContainer {
 	int texture2d_array_node_option_idx;
 	int texture3d_node_option_idx;
 	int custom_node_option_idx;
+	int curve_node_option_idx;
 	List<String> keyword_list;
 
 	List<VisualShaderNodeUniformRef> uniform_refs;
@@ -265,6 +270,8 @@ class VisualShaderEditor : public VBoxContainer {
 	void _add_texture2d_node(const String &p_path);
 	void _add_texture2d_array_node(const String &p_path);
 	void _add_texture3d_node(const String &p_path);
+	void _add_curve_node(const String &p_path);
+
 	VisualShaderNode *_add_node(int p_idx, int p_op_idx = -1);
 	void _update_options_menu();
 	void _set_mode(int p_which);

+ 3 - 1
scene/register_scene_types.cpp

@@ -522,7 +522,8 @@ void register_scene_types() {
 	ClassDB::register_class<VisualShaderNodeCustom>();
 	ClassDB::register_class<VisualShaderNodeInput>();
 	ClassDB::register_virtual_class<VisualShaderNodeOutput>();
-	ClassDB::register_class<VisualShaderNodeGroupBase>();
+	ClassDB::register_virtual_class<VisualShaderNodeResizableBase>();
+	ClassDB::register_virtual_class<VisualShaderNodeGroupBase>();
 	ClassDB::register_class<VisualShaderNodeFloatConstant>();
 	ClassDB::register_class<VisualShaderNodeIntConstant>();
 	ClassDB::register_class<VisualShaderNodeBooleanConstant>();
@@ -563,6 +564,7 @@ void register_scene_types() {
 	ClassDB::register_class<VisualShaderNodeVectorDecompose>();
 	ClassDB::register_class<VisualShaderNodeTransformDecompose>();
 	ClassDB::register_class<VisualShaderNodeTexture>();
+	ClassDB::register_class<VisualShaderNodeCurveTexture>();
 	ClassDB::register_virtual_class<VisualShaderNodeSample3D>();
 	ClassDB::register_class<VisualShaderNodeTexture2DArray>();
 	ClassDB::register_class<VisualShaderNodeTexture3D>();

+ 26 - 14
scene/resources/visual_shader.cpp

@@ -992,7 +992,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
 			set_node_position(type, id, p_value);
 			return true;
 		} else if (what == "size") {
-			((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_size(p_value);
+			((VisualShaderNodeResizableBase *)get_node(type, id).ptr())->set_size(p_value);
 			return true;
 		} else if (what == "input_ports") {
 			((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_inputs(p_value);
@@ -1059,7 +1059,7 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
 			r_ret = get_node_position(type, id);
 			return true;
 		} else if (what == "size") {
-			r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_size();
+			r_ret = ((VisualShaderNodeResizableBase *)get_node(type, id).ptr())->get_size();
 			return true;
 		} else if (what == "input_ports") {
 			r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_inputs();
@@ -2597,20 +2597,37 @@ Vector<StringName> VisualShaderNodeUniform::get_editable_properties() const {
 VisualShaderNodeUniform::VisualShaderNodeUniform() {
 }
 
-////////////// GroupBase
-
-String VisualShaderNodeGroupBase::get_caption() const {
-	return "Group";
-}
+////////////// ResizeableBase
 
-void VisualShaderNodeGroupBase::set_size(const Vector2 &p_size) {
+void VisualShaderNodeResizableBase::set_size(const Vector2 &p_size) {
 	size = p_size;
 }
 
-Vector2 VisualShaderNodeGroupBase::get_size() const {
+Vector2 VisualShaderNodeResizableBase::get_size() const {
 	return size;
 }
 
+void VisualShaderNodeResizableBase::set_allow_v_resize(bool p_enabled) {
+	allow_v_resize = p_enabled;
+}
+
+bool VisualShaderNodeResizableBase::is_allow_v_resize() const {
+	return allow_v_resize;
+}
+
+void VisualShaderNodeResizableBase::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeResizableBase::set_size);
+	ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeResizableBase::get_size);
+
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+}
+
+VisualShaderNodeResizableBase::VisualShaderNodeResizableBase() {
+	set_allow_v_resize(true);
+}
+
+////////////// GroupBase
+
 void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) {
 	if (inputs == p_inputs) {
 		return;
@@ -3037,9 +3054,6 @@ bool VisualShaderNodeGroupBase::is_editable() const {
 }
 
 void VisualShaderNodeGroupBase::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size);
-	ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeGroupBase::get_size);
-
 	ClassDB::bind_method(D_METHOD("set_inputs", "inputs"), &VisualShaderNodeGroupBase::set_inputs);
 	ClassDB::bind_method(D_METHOD("get_inputs"), &VisualShaderNodeGroupBase::get_inputs);
 
@@ -3067,8 +3081,6 @@ void VisualShaderNodeGroupBase::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("get_free_input_port_id"), &VisualShaderNodeGroupBase::get_free_input_port_id);
 	ClassDB::bind_method(D_METHOD("get_free_output_port_id"), &VisualShaderNodeGroupBase::get_free_output_port_id);
-
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
 }
 
 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 {

+ 22 - 8
scene/resources/visual_shader.h

@@ -486,14 +486,33 @@ public:
 	VisualShaderNodeUniformRef();
 };
 
-class VisualShaderNodeGroupBase : public VisualShaderNode {
-	GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode);
+class VisualShaderNodeResizableBase : public VisualShaderNode {
+	GDCLASS(VisualShaderNodeResizableBase, VisualShaderNode);
+
+protected:
+	Vector2 size = Size2(0, 0);
+	bool allow_v_resize = true;
+
+protected:
+	static void _bind_methods();
+
+public:
+	void set_size(const Vector2 &p_size);
+	Vector2 get_size() const;
+
+	bool is_allow_v_resize() const;
+	void set_allow_v_resize(bool p_enabled);
+
+	VisualShaderNodeResizableBase();
+};
+
+class VisualShaderNodeGroupBase : public VisualShaderNodeResizableBase {
+	GDCLASS(VisualShaderNodeGroupBase, VisualShaderNodeResizableBase);
 
 private:
 	void _apply_port_changes();
 
 protected:
-	Vector2 size = Size2(0, 0);
 	String inputs = "";
 	String outputs = "";
 	bool editable = false;
@@ -511,11 +530,6 @@ protected:
 	static void _bind_methods();
 
 public:
-	virtual String get_caption() const override;
-
-	void set_size(const Vector2 &p_size);
-	Vector2 get_size() const;
-
 	void set_inputs(const String &p_inputs);
 	String get_inputs() const;
 

+ 84 - 0
scene/resources/visual_shader_nodes.cpp

@@ -782,6 +782,90 @@ void VisualShaderNodeTexture::_bind_methods() {
 VisualShaderNodeTexture::VisualShaderNodeTexture() {
 }
 
+////////////// Curve
+
+String VisualShaderNodeCurveTexture::get_caption() const {
+	return "CurveTexture";
+}
+
+int VisualShaderNodeCurveTexture::get_input_port_count() const {
+	return 1;
+}
+
+VisualShaderNodeCurveTexture::PortType VisualShaderNodeCurveTexture::get_input_port_type(int p_port) const {
+	return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeCurveTexture::get_input_port_name(int p_port) const {
+	return String();
+}
+
+int VisualShaderNodeCurveTexture::get_output_port_count() const {
+	return 1;
+}
+
+VisualShaderNodeCurveTexture::PortType VisualShaderNodeCurveTexture::get_output_port_type(int p_port) const {
+	return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeCurveTexture::get_output_port_name(int p_port) const {
+	return String();
+}
+
+void VisualShaderNodeCurveTexture::set_texture(Ref<CurveTexture> p_texture) {
+	texture = p_texture;
+	emit_changed();
+}
+
+Ref<CurveTexture> VisualShaderNodeCurveTexture::get_texture() const {
+	return texture;
+}
+
+Vector<StringName> VisualShaderNodeCurveTexture::get_editable_properties() const {
+	Vector<StringName> props;
+	props.push_back("texture");
+	return props;
+}
+
+String VisualShaderNodeCurveTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+	return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + ";\n";
+}
+
+String VisualShaderNodeCurveTexture::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 {
+	if (p_input_vars[0] == String()) {
+		return "\t" + p_output_vars[0] + " = 0.0;\n";
+	}
+	String id = make_unique_id(p_type, p_id, "curve");
+	String code;
+	code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ", 0.0)).r;\n";
+	return code;
+}
+
+Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCurveTexture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
+	VisualShader::DefaultTextureParam dtp;
+	dtp.name = make_unique_id(p_type, p_id, "curve");
+	dtp.param = texture;
+	Vector<VisualShader::DefaultTextureParam> ret;
+	ret.push_back(dtp);
+	return ret;
+}
+
+void VisualShaderNodeCurveTexture::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_texture", "texture"), &VisualShaderNodeCurveTexture::set_texture);
+	ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeCurveTexture::get_texture);
+
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_texture", "get_texture");
+}
+
+bool VisualShaderNodeCurveTexture::is_use_prop_slots() const {
+	return true;
+}
+
+VisualShaderNodeCurveTexture::VisualShaderNodeCurveTexture() {
+	simple_decl = true;
+	allow_v_resize = false;
+}
+
 ////////////// Sample3D
 
 int VisualShaderNodeSample3D::get_input_port_count() const {

+ 33 - 0
scene/resources/visual_shader_nodes.h

@@ -284,6 +284,39 @@ VARIANT_ENUM_CAST(VisualShaderNodeTexture::Source)
 
 ///////////////////////////////////////
 
+class VisualShaderNodeCurveTexture : public VisualShaderNodeResizableBase {
+	GDCLASS(VisualShaderNodeCurveTexture, VisualShaderNodeResizableBase);
+	Ref<CurveTexture> texture;
+
+protected:
+	static void _bind_methods();
+
+public:
+	virtual String get_caption() const override;
+
+	virtual int get_input_port_count() const override;
+	virtual PortType get_input_port_type(int p_port) const override;
+	virtual String get_input_port_name(int p_port) const override;
+
+	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 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;
+	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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+
+	void set_texture(Ref<CurveTexture> p_value);
+	Ref<CurveTexture> get_texture() const;
+
+	virtual Vector<StringName> get_editable_properties() const override;
+	virtual bool is_use_prop_slots() const override;
+
+	VisualShaderNodeCurveTexture();
+};
+
+///////////////////////////////////////
+
 class VisualShaderNodeSample3D : public VisualShaderNode {
 	GDCLASS(VisualShaderNodeSample3D, VisualShaderNode);