Răsfoiți Sursa

Rework GraphEdit connections (drawing, API, optimizations)
- GraphEdit now uses Line2D nodes to draw connection lines and uses a dedicated canvas item shader for them

Hendrik Brucker 1 an în urmă
părinte
comite
9d7c2978f4

+ 26 - 0
core/math/geometry_2d.h

@@ -119,6 +119,10 @@ public:
 		}
 	}
 
+	static real_t get_distance_to_segment(const Vector2 &p_point, const Vector2 *p_segment) {
+		return p_point.distance_to(get_closest_point_to_segment(p_point, p_segment));
+	}
+
 	static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) {
 		Vector2 an = a - s;
 		Vector2 bn = b - s;
@@ -249,6 +253,28 @@ public:
 		return -1;
 	}
 
+	static bool segment_intersects_rect(const Vector2 &p_from, const Vector2 &p_to, const Rect2 &p_rect) {
+		if (p_rect.has_point(p_from) || p_rect.has_point(p_to)) {
+			return true;
+		}
+
+		const Vector2 rect_points[4] = {
+			p_rect.position,
+			p_rect.position + Vector2(p_rect.size.x, 0),
+			p_rect.position + p_rect.size,
+			p_rect.position + Vector2(0, p_rect.size.y)
+		};
+
+		// Check if any of the rect's edges intersect the segment.
+		for (int i = 0; i < 4; i++) {
+			if (segment_intersects_segment(p_from, p_to, rect_points[i], rect_points[(i + 1) % 4], nullptr)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
 	enum PolyBooleanOperation {
 		OPERATION_UNION,
 		OPERATION_DIFFERENCE,

+ 35 - 4
doc/classes/GraphEdit.xml

@@ -143,7 +143,22 @@
 				[b]Note:[/b] This method suppresses any other connection request signals apart from [signal connection_drag_ended].
 			</description>
 		</method>
-		<method name="get_connection_line">
+		<method name="get_closest_connection_at_point" qualifiers="const">
+			<return type="Dictionary" />
+			<param index="0" name="point" type="Vector2" />
+			<param index="1" name="max_distance" type="float" default="4.0" />
+			<description>
+				Returns the closest connection to the given point in screen space. If no connection is found within [param max_distance] pixels, an empty [Dictionary] is returned.
+				A connection consists in a structure of the form [code]{ from_port: 0, from_node: "GraphNode name 0", to_port: 1, to_node: "GraphNode name 1" }[/code].
+				For example, getting a connection at a given mouse position can be achieved like this:
+				[codeblocks]
+				[gdscript]
+				var connection = get_closest_connection_at_point(mouse_event.get_position())
+				[/gdscript]
+				[/codeblocks]
+			</description>
+		</method>
+		<method name="get_connection_line" qualifiers="const">
 			<return type="PackedVector2Array" />
 			<param index="0" name="from_node" type="Vector2" />
 			<param index="1" name="to_node" type="Vector2" />
@@ -154,7 +169,14 @@
 		<method name="get_connection_list" qualifiers="const">
 			<return type="Dictionary[]" />
 			<description>
-				Returns an Array containing the list of connections. A connection consists in a structure of the form [code]{ from_port: 0, from_node: "GraphNode name 0", to_port: 1, to_node: "GraphNode name 1" }[/code].
+				Returns an [Array] containing the list of connections. A connection consists in a structure of the form [code]{ from_port: 0, from_node: "GraphNode name 0", to_port: 1, to_node: "GraphNode name 1" }[/code].
+			</description>
+		</method>
+		<method name="get_connections_intersecting_with_rect" qualifiers="const">
+			<return type="Dictionary[]" />
+			<param index="0" name="rect" type="Rect2" />
+			<description>
+				Returns an [Array] containing the list of connections that intersect with the given [Rect2]. A connection consists in a structure of the form [code]{ from_port: 0, from_node: "GraphNode name 0", to_port: 1, to_node: "GraphNode name 1" }[/code].
 			</description>
 		</method>
 		<method name="get_menu_hbox">
@@ -233,7 +255,7 @@
 		<member name="connection_lines_curvature" type="float" setter="set_connection_lines_curvature" getter="get_connection_lines_curvature" default="0.5">
 			The curvature of the lines between the nodes. 0 results in straight lines.
 		</member>
-		<member name="connection_lines_thickness" type="float" setter="set_connection_lines_thickness" getter="get_connection_lines_thickness" default="2.0">
+		<member name="connection_lines_thickness" type="float" setter="set_connection_lines_thickness" getter="get_connection_lines_thickness" default="4.0">
 			The thickness of the lines between the nodes.
 		</member>
 		<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
@@ -417,7 +439,16 @@
 	</constants>
 	<theme_items>
 		<theme_item name="activity" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
-			Color of the connection's activity (see [method set_connection_activity]).
+			Color the connection line is interpolated to based on the activity value of a connection (see [method set_connection_activity]).
+		</theme_item>
+		<theme_item name="connection_hover_tint_color" data_type="color" type="Color" default="Color(0, 0, 0, 0.3)">
+			Color which is blended with the connection line when the mouse is hovering over it.
+		</theme_item>
+		<theme_item name="connection_rim_color" data_type="color" type="Color" default="Color(0.1, 0.1, 0.1, 0.6)">
+			Color of the rim around each connection line used for making intersecting lines more distinguishable.
+		</theme_item>
+		<theme_item name="connection_valid_target_tint_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.4)">
+			Color which is blended with the connection line when the currently dragged connection is hovering over a valid target port.
 		</theme_item>
 		<theme_item name="grid_major" data_type="color" type="Color" default="Color(1, 1, 1, 0.2)">
 			Color of major grid lines/dots.

+ 4 - 0
editor/themes/editor_theme_manager.cpp

@@ -1367,6 +1367,10 @@ void EditorThemeManager::_populate_standard_styles(const Ref<Theme> &p_theme, Th
 		p_theme->set_color("selection_stroke", "GraphEdit", p_theme->get_color(SNAME("box_selection_stroke_color"), EditorStringName(Editor)));
 		p_theme->set_color("activity", "GraphEdit", p_config.accent_color);
 
+		p_theme->set_color("connection_hover_tint_color", "GraphEdit", p_config.dark_theme ? Color(0, 0, 0, 0.3) : Color(1, 1, 1, 0.3));
+		p_theme->set_color("connection_valid_target_tint_color", "GraphEdit", p_config.dark_theme ? Color(1, 1, 1, 0.4) : Color(0, 0, 0, 0.4));
+		p_theme->set_color("connection_rim_color", "GraphEdit", p_config.tree_panel_style->get_bg_color());
+
 		p_theme->set_icon("zoom_out", "GraphEdit", p_theme->get_icon(SNAME("ZoomLess"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("zoom_in", "GraphEdit", p_theme->get_icon(SNAME("ZoomMore"), EditorStringName(EditorIcons)));
 		p_theme->set_icon("zoom_reset", "GraphEdit", p_theme->get_icon(SNAME("ZoomReset"), EditorStringName(EditorIcons)));

+ 7 - 0
misc/extension_api_validation/4.2-stable.expected

@@ -59,3 +59,10 @@ Validate extension JSON: Error: Field 'classes/TileMap/methods/get_collision_vis
 Validate extension JSON: Error: Field 'classes/TileMap/methods/get_navigation_visibility_mode': is_const changed value in new API, from false to true.
 
 Two TileMap getters were made const. No adjustments should be necessary.
+
+
+GH-86158
+--------
+Validate extension JSON: Error: Field 'classes/GraphEdit/methods/get_connection_line': is_const changed value in new API, from false to true.
+
+get_connection_line was made const.

+ 5 - 0
scene/gui/graph_edit.compat.inc

@@ -38,9 +38,14 @@ void GraphEdit::_set_arrange_nodes_button_hidden_bind_compat_81582(bool p_enable
 	set_show_arrange_button(!p_enable);
 }
 
+PackedVector2Array GraphEdit::_get_connection_line_bind_compat_86158(const Vector2 &p_from, const Vector2 &p_to) {
+	return get_connection_line(p_from, p_to);
+}
+
 void GraphEdit::_bind_compatibility_methods() {
 	ClassDB::bind_compatibility_method(D_METHOD("is_arrange_nodes_button_hidden"), &GraphEdit::_is_arrange_nodes_button_hidden_bind_compat_81582);
 	ClassDB::bind_compatibility_method(D_METHOD("set_arrange_nodes_button_hidden", "enable"), &GraphEdit::_set_arrange_nodes_button_hidden_bind_compat_81582);
+	ClassDB::bind_compatibility_method(D_METHOD("get_connection_line", "from_node", "to_node"), &GraphEdit::_get_connection_line_bind_compat_86158);
 }
 
 #endif

Fișier diff suprimat deoarece este prea mare
+ 468 - 189
scene/gui/graph_edit.cpp


+ 62 - 20
scene/gui/graph_edit.h

@@ -39,6 +39,7 @@ class GraphEdit;
 class GraphEditArranger;
 class HScrollBar;
 class Label;
+class Line2D;
 class PanelContainer;
 class SpinBox;
 class ViewPanner;
@@ -112,12 +113,25 @@ class GraphEdit : public Control {
 	GDCLASS(GraphEdit, Control);
 
 public:
-	struct Connection {
+	struct Connection : RefCounted {
 		StringName from_node;
 		StringName to_node;
 		int from_port = 0;
 		int to_port = 0;
 		float activity = 0.0;
+
+	private:
+		struct Cache {
+			bool dirty = true;
+			Vector2 from_pos; // In graph space.
+			Vector2 to_pos; // In graph space.
+			Color from_color;
+			Color to_color;
+			Rect2 aabb; // In local screen space.
+			Line2D *line = nullptr; // In local screen space.
+		} _cache;
+
+		friend class GraphEdit;
 	};
 
 	// Should be in sync with ControlScheme in ViewPanner.
@@ -184,15 +198,15 @@ private:
 	GridPattern grid_pattern = GRID_PATTERN_LINES;
 
 	bool connecting = false;
-	String connecting_from;
-	bool connecting_out = false;
-	int connecting_index = 0;
+	StringName connecting_from_node;
+	bool connecting_from_output = false;
 	int connecting_type = 0;
 	Color connecting_color;
-	bool connecting_target = false;
-	Vector2 connecting_to;
-	StringName connecting_target_to;
-	int connecting_target_index = 0;
+	Vector2 connecting_to_point; // In local screen space.
+	bool connecting_target_valid = false;
+	StringName connecting_target_node;
+	int connecting_from_port_index = 0;
+	int connecting_target_port_index = 0;
 
 	bool just_disconnected = false;
 	bool connecting_valid = false;
@@ -222,18 +236,28 @@ private:
 	bool right_disconnects = false;
 	bool updating = false;
 	bool awaiting_scroll_offset_update = false;
-	List<Connection> connections;
 
-	float lines_thickness = 2.0f;
+	List<Ref<Connection>> connections;
+	HashMap<StringName, List<Ref<Connection>>> connection_map;
+	Ref<Connection> hovered_connection;
+
+	float lines_thickness = 4.0f;
 	float lines_curvature = 0.5f;
 	bool lines_antialiased = true;
 
 	PanelContainer *menu_panel = nullptr;
 	HBoxContainer *menu_hbox = nullptr;
 	Control *connections_layer = nullptr;
-	GraphEditFilter *top_layer = nullptr;
+
+	GraphEditFilter *top_connection_layer = nullptr; // Draws a dragged connection. Necessary since the connection line shader can't be applied to the whole top layer.
+	Line2D *dragged_connection_line = nullptr;
+	Control *top_layer = nullptr; // Used for drawing the box selection rect. Contains the minimap, menu panel and the scrollbars.
+
 	GraphEditMinimap *minimap = nullptr;
 
+	static Ref<Shader> default_connections_shader;
+	Ref<Shader> connections_shader;
+
 	Ref<GraphEditArranger> arranger;
 
 	HashSet<ConnectionType, ConnectionType> valid_connection_types;
@@ -248,6 +272,10 @@ private:
 		Color grid_minor;
 
 		Color activity_color;
+		Color connection_hover_tint_color;
+		Color connection_valid_target_tint_color;
+		Color connection_rim_color;
+
 		Color selection_fill;
 		Color selection_stroke;
 
@@ -274,30 +302,35 @@ private:
 	void _zoom_plus();
 	void _update_zoom_label();
 
-	void _draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom);
-
 	void _graph_element_selected(Node *p_node);
 	void _graph_element_deselected(Node *p_node);
 	void _graph_element_moved_to_front(Node *p_node);
 	void _graph_element_resized(Vector2 p_new_minsize, Node *p_node);
 	void _graph_element_moved(Node *p_node);
 	void _graph_node_slot_updated(int p_index, Node *p_node);
+	void _graph_node_rect_changed(GraphNode *p_node);
 
 	void _update_scroll();
 	void _update_scroll_offset();
 	void _scroll_moved(double);
 	virtual void gui_input(const Ref<InputEvent> &p_ev) override;
-	void _top_layer_input(const Ref<InputEvent> &p_ev);
+	void _top_connection_layer_input(const Ref<InputEvent> &p_ev);
 
-	bool is_in_port_hotzone(const Vector2 &p_pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
+	float _get_shader_line_width();
+	void _draw_minimap_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color);
+	void _invalidate_connection_line_cache();
+	void _update_top_connection_layer();
+	void _update_connections();
 
 	void _top_layer_draw();
-	void _connections_layer_draw();
 	void _minimap_draw();
-
 	void _draw_grid();
 
+	bool is_in_port_hotzone(const Vector2 &p_pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
+
 	TypedArray<Dictionary> _get_connection_list() const;
+	Dictionary _get_closest_connection_at_point(const Vector2 &p_point, float p_max_distance = 4.0) const;
+	TypedArray<Dictionary> _get_connections_intersecting_with_rect(const Rect2 &p_rect) const;
 
 	friend class GraphEditFilter;
 	bool _filter_input(const Point2 &p_point);
@@ -313,6 +346,7 @@ private:
 #ifndef DISABLE_DEPRECATED
 	bool _is_arrange_nodes_button_hidden_bind_compat_81582() const;
 	void _set_arrange_nodes_button_hidden_bind_compat_81582(bool p_enable);
+	PackedVector2Array _get_connection_line_bind_compat_86158(const Vector2 &p_from, const Vector2 &p_to);
 #endif
 
 protected:
@@ -336,6 +370,9 @@ protected:
 	GDVIRTUAL4R(bool, _is_node_hover_valid, StringName, int, StringName, int);
 
 public:
+	static void init_shaders();
+	static void finish_shaders();
+
 	virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
 
 	PackedStringArray get_configuration_warnings() const override;
@@ -344,12 +381,17 @@ public:
 	bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
 	void disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
 	void clear_connections();
+
 	void force_connection_drag_end();
+	const List<Ref<Connection>> &get_connection_list() const;
+	virtual PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to) const;
+	Ref<Connection> get_closest_connection_at_point(const Vector2 &p_point, float p_max_distance = 4.0) const;
+	List<Ref<Connection>> get_connections_intersecting_with_rect(const Rect2 &p_rect) const;
 
-	virtual PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to);
 	virtual bool is_node_hover_valid(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
 
 	void set_connection_activity(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port, float p_activity);
+	void reset_all_connection_activity();
 
 	void add_valid_connection_type(int p_type, int p_with_type);
 	void remove_valid_connection_type(int p_type, int p_with_type);
@@ -392,10 +434,10 @@ public:
 	void set_show_arrange_button(bool p_hidden);
 	bool is_showing_arrange_button() const;
 
-	GraphEditFilter *get_top_layer() const { return top_layer; }
+	Control *get_top_layer() const { return top_layer; }
 	GraphEditMinimap *get_minimap() const { return minimap; }
 
-	void get_connection_list(List<Connection> *r_connections) const;
+	void override_connections_shader(const Ref<Shader> &p_shader);
 
 	void set_right_disconnects(bool p_enable);
 	bool is_right_disconnects_enabled() const;

+ 31 - 33
scene/gui/graph_edit_arranger.cpp

@@ -65,8 +65,7 @@ void GraphEditArranger::arrange_nodes() {
 	float gap_v = 100.0f;
 	float gap_h = 100.0f;
 
-	List<GraphEdit::Connection> connection_list;
-	graph_edit->get_connection_list(&connection_list);
+	List<Ref<GraphEdit::Connection>> connection_list = graph_edit->get_connection_list();
 
 	for (int i = graph_edit->get_child_count() - 1; i >= 0; i--) {
 		GraphNode *graph_element = Object::cast_to<GraphNode>(graph_edit->get_child(i));
@@ -77,15 +76,16 @@ void GraphEditArranger::arrange_nodes() {
 		if (graph_element->is_selected() || arrange_entire_graph) {
 			selected_nodes.insert(graph_element->get_name());
 			HashSet<StringName> s;
-			for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
-				GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from_node]);
-				if (E->get().to_node == graph_element->get_name() && (p_from->is_selected() || arrange_entire_graph) && E->get().to_node != E->get().from_node) {
+
+			for (const Ref<GraphEdit::Connection> &connection : connection_list) {
+				GraphNode *p_from = Object::cast_to<GraphNode>(node_names[connection->from_node]);
+				if (connection->to_node == graph_element->get_name() && (p_from->is_selected() || arrange_entire_graph) && connection->to_node != connection->from_node) {
 					if (!s.has(p_from->get_name())) {
 						s.insert(p_from->get_name());
 					}
-					String s_connection = String(p_from->get_name()) + " " + String(E->get().to_node);
+					String s_connection = String(p_from->get_name()) + " " + String(connection->to_node);
 					StringName _connection(s_connection);
-					Pair<int, int> ports(E->get().from_port, E->get().to_port);
+					Pair<int, int> ports(connection->from_port, connection->to_port);
 					port_info.insert(_connection, ports);
 				}
 			}
@@ -437,31 +437,30 @@ float GraphEditArranger::_calculate_threshold(const StringName &p_v, const Strin
 	float threshold = p_current_threshold;
 	if (p_v == p_w) {
 		int min_order = MAX_ORDER;
-		GraphEdit::Connection incoming;
-		List<GraphEdit::Connection> connection_list;
-		graph_edit->get_connection_list(&connection_list);
-		for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
-			if (E->get().to_node == p_w) {
-				ORDER(E->get().from_node, r_layers);
+		Ref<GraphEdit::Connection> incoming;
+		List<Ref<GraphEdit::Connection>> connection_list = graph_edit->get_connection_list();
+		for (const Ref<GraphEdit::Connection> &connection : connection_list) {
+			if (connection->to_node == p_w) {
+				ORDER(connection->from_node, r_layers);
 				if (min_order > order) {
 					min_order = order;
-					incoming = E->get();
+					incoming = connection;
 				}
 			}
 		}
 
-		if (incoming.from_node != StringName()) {
-			GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[incoming.from_node]);
+		if (incoming.is_valid()) {
+			GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[incoming->from_node]);
 			GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[p_w]);
-			Vector2 pos_from = gnode_from->get_output_port_position(incoming.from_port) * graph_edit->get_zoom();
-			Vector2 pos_to = gnode_to->get_input_port_position(incoming.to_port) * graph_edit->get_zoom();
+			Vector2 pos_from = gnode_from->get_output_port_position(incoming->from_port) * graph_edit->get_zoom();
+			Vector2 pos_to = gnode_to->get_input_port_position(incoming->to_port) * graph_edit->get_zoom();
 
 			// If connected block node is selected, calculate thershold or add current block to list.
 			if (gnode_from->is_selected()) {
-				Vector2 connected_block_pos = r_node_positions[r_root[incoming.from_node]];
+				Vector2 connected_block_pos = r_node_positions[r_root[incoming->from_node]];
 				if (connected_block_pos.y != FLT_MAX) {
 					//Connected block is placed, calculate threshold.
-					threshold = connected_block_pos.y + (real_t)r_inner_shift[incoming.from_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
+					threshold = connected_block_pos.y + (real_t)r_inner_shift[incoming->from_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
 				}
 			}
 		}
@@ -469,31 +468,30 @@ float GraphEditArranger::_calculate_threshold(const StringName &p_v, const Strin
 	if (threshold == FLT_MIN && (StringName)r_align[p_w] == p_v) {
 		// This time, pick an outgoing edge and repeat as above!
 		int min_order = MAX_ORDER;
-		GraphEdit::Connection outgoing;
-		List<GraphEdit::Connection> connection_list;
-		graph_edit->get_connection_list(&connection_list);
-		for (List<GraphEdit::Connection>::Element *E = connection_list.front(); E; E = E->next()) {
-			if (E->get().from_node == p_w) {
-				ORDER(E->get().to_node, r_layers);
+		Ref<GraphEdit::Connection> outgoing;
+		List<Ref<GraphEdit::Connection>> connection_list = graph_edit->get_connection_list();
+		for (const Ref<GraphEdit::Connection> &connection : connection_list) {
+			if (connection->from_node == p_w) {
+				ORDER(connection->to_node, r_layers);
 				if (min_order > order) {
 					min_order = order;
-					outgoing = E->get();
+					outgoing = connection;
 				}
 			}
 		}
 
-		if (outgoing.to_node != StringName()) {
+		if (outgoing.is_valid()) {
 			GraphNode *gnode_from = Object::cast_to<GraphNode>(r_node_names[p_w]);
-			GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[outgoing.to_node]);
-			Vector2 pos_from = gnode_from->get_output_port_position(outgoing.from_port) * graph_edit->get_zoom();
-			Vector2 pos_to = gnode_to->get_input_port_position(outgoing.to_port) * graph_edit->get_zoom();
+			GraphNode *gnode_to = Object::cast_to<GraphNode>(r_node_names[outgoing->to_node]);
+			Vector2 pos_from = gnode_from->get_output_port_position(outgoing->from_port) * graph_edit->get_zoom();
+			Vector2 pos_to = gnode_to->get_input_port_position(outgoing->to_port) * graph_edit->get_zoom();
 
 			// If connected block node is selected, calculate thershold or add current block to list.
 			if (gnode_to->is_selected()) {
-				Vector2 connected_block_pos = r_node_positions[r_root[outgoing.to_node]];
+				Vector2 connected_block_pos = r_node_positions[r_root[outgoing->to_node]];
 				if (connected_block_pos.y != FLT_MAX) {
 					//Connected block is placed. Calculate threshold
-					threshold = connected_block_pos.y + (real_t)r_inner_shift[outgoing.to_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
+					threshold = connected_block_pos.y + (real_t)r_inner_shift[outgoing->to_node] - (real_t)r_inner_shift[p_w] + pos_from.y - pos_to.y;
 				}
 			}
 		}

+ 4 - 1
scene/register_scene_types.cpp

@@ -1184,7 +1184,9 @@ void register_scene_types() {
 	}
 
 	if (RenderingServer::get_singleton()) {
-		ColorPicker::init_shaders(); // RenderingServer needs to exist for this to succeed.
+		// RenderingServer needs to exist for this to succeed.
+		ColorPicker::init_shaders();
+		GraphEdit::init_shaders();
 	}
 
 	SceneDebugger::initialize();
@@ -1236,6 +1238,7 @@ void unregister_scene_types() {
 	ParticleProcessMaterial::finish_shaders();
 	CanvasItemMaterial::finish_shaders();
 	ColorPicker::finish_shaders();
+	GraphEdit::finish_shaders();
 	SceneStringNames::free();
 
 	OS::get_singleton()->benchmark_end_measure("Scene", "Unregister Types");

+ 3 - 0
scene/theme/default_theme.cpp

@@ -1161,6 +1161,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3));
 	theme->set_color("selection_stroke", "GraphEdit", Color(1, 1, 1, 0.8));
 	theme->set_color("activity", "GraphEdit", Color(1, 1, 1));
+	theme->set_color("connection_hover_tint_color", "GraphEdit", Color(0, 0, 0, 0.3));
+	theme->set_color("connection_valid_target_tint_color", "GraphEdit", Color(1, 1, 1, 0.4));
+	theme->set_color("connection_rim_color", "GraphEdit", style_normal_color);
 
 	// Visual Node Ports
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff