diff options
90 files changed, 905 insertions, 670 deletions
diff --git a/.editorconfig b/.editorconfig index 92ee947a82..4bb7553b16 100644 --- a/.editorconfig +++ b/.editorconfig @@ -21,3 +21,13 @@ indent_size = 4  [*.{yml,yaml}]  indent_style = space  indent_size = 2 + +# GDScript unit test files +[*.gd] +indent_style = tab +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.out] +insert_final_newline = true diff --git a/core/object/object.cpp b/core/object/object.cpp index 1f0a7e516d..2cb56dfe6c 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1055,7 +1055,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int  				if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) {  					//most likely object is not initialized yet, do not throw error.  				} else { -					ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc + c.callable.get_bound_arguments_count(), ce) + "."); +					ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc, ce) + ".");  					err = ERR_METHOD_NOT_FOUND;  				}  			} diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index fd85fe78f6..2f2acc55a6 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -117,6 +117,7 @@ Callable Callable::bindv(const Array &p_arguments) {  }  Callable Callable::unbind(int p_argcount) const { +	ERR_FAIL_COND_V_MSG(p_argcount <= 0, Callable(*this), "Amount of unbind() arguments must be 1 or greater.");  	return Callable(memnew(CallableCustomUnbind(*this, p_argcount)));  } @@ -159,6 +160,27 @@ int Callable::get_bound_arguments_count() const {  	}  } +void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const { +	if (!is_null() && is_custom()) { +		custom->get_bound_arguments(r_arguments, r_argcount); +	} else { +		r_arguments.clear(); +		r_argcount = 0; +	} +} + +Array Callable::get_bound_arguments() const { +	Vector<Variant> arr; +	int ac; +	get_bound_arguments_ref(arr, ac); +	Array ret; +	ret.resize(arr.size()); +	for (int i = 0; i < arr.size(); i++) { +		ret[i] = arr[i]; +	} +	return ret; +} +  CallableCustom *Callable::get_custom() const {  	ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,  			vformat("Can't get custom on non-CallableCustom \"%s\".", operator String())); @@ -370,6 +392,11 @@ int CallableCustom::get_bound_arguments_count() const {  	return 0;  } +void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const { +	r_arguments = Vector<Variant>(); +	r_argcount = 0; +} +  CallableCustom::CallableCustom() {  	ref_count.init();  } diff --git a/core/variant/callable.h b/core/variant/callable.h index 10d291ac24..0abbb64c0b 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -108,6 +108,8 @@ public:  	StringName get_method() const;  	CallableCustom *get_custom() const;  	int get_bound_arguments_count() const; +	void get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const; // Internal engine use, the exposed one is below. +	Array get_bound_arguments() const;  	uint32_t hash() const; @@ -149,6 +151,7 @@ public:  	virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const;  	virtual const Callable *get_base_comparator() const;  	virtual int get_bound_arguments_count() const; +	virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const;  	CallableCustom();  	virtual ~CallableCustom() {} diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp index 83035dc70d..5be91c6e11 100644 --- a/core/variant/callable_bind.cpp +++ b/core/variant/callable_bind.cpp @@ -91,6 +91,43 @@ int CallableCustomBind::get_bound_arguments_count() const {  	return callable.get_bound_arguments_count() + binds.size();  } +void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const { +	Vector<Variant> sub_args; +	int sub_count; +	callable.get_bound_arguments_ref(sub_args, sub_count); + +	if (sub_count == 0) { +		r_arguments = binds; +		r_argcount = binds.size(); +		return; +	} + +	int new_count = sub_count + binds.size(); +	r_argcount = new_count; + +	if (new_count <= 0) { +		// Removed more arguments than it adds. +		r_arguments = Vector<Variant>(); +		return; +	} + +	r_arguments.resize(new_count); + +	if (sub_count > 0) { +		for (int i = 0; i < sub_count; i++) { +			r_arguments.write[i] = sub_args[i]; +		} +		for (int i = 0; i < binds.size(); i++) { +			r_arguments.write[i + sub_count] = binds[i]; +		} +		r_argcount = new_count; +	} else { +		for (int i = 0; i < binds.size() + sub_count; i++) { +			r_arguments.write[i] = binds[i - sub_count]; +		} +	} +} +  void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {  	const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * (binds.size() + p_argcount));  	for (int i = 0; i < p_argcount; i++) { @@ -172,6 +209,21 @@ int CallableCustomUnbind::get_bound_arguments_count() const {  	return callable.get_bound_arguments_count() - argcount;  } +void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const { +	Vector<Variant> sub_args; +	int sub_count; +	callable.get_bound_arguments_ref(sub_args, sub_count); + +	r_argcount = sub_args.size() - argcount; + +	if (argcount >= sub_args.size()) { +		r_arguments = Vector<Variant>(); +	} else { +		sub_args.resize(sub_args.size() - argcount); +		r_arguments = sub_args; +	} +} +  void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {  	if (argcount > p_argcount) {  		r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h index a79a521b5b..278ed335d0 100644 --- a/core/variant/callable_bind.h +++ b/core/variant/callable_bind.h @@ -52,6 +52,7 @@ public:  	virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;  	virtual const Callable *get_base_comparator() const override;  	virtual int get_bound_arguments_count() const override; +	virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;  	Callable get_callable() { return callable; }  	Vector<Variant> get_binds() { return binds; } @@ -77,6 +78,7 @@ public:  	virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;  	virtual const Callable *get_base_comparator() const override;  	virtual int get_bound_arguments_count() const override; +	virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;  	Callable get_callable() { return callable; }  	int get_unbinds() { return argcount; } diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index bff6656a88..ca42738b05 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3654,7 +3654,22 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,  }  String Variant::get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) { -	return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, p_argcount, ce); +	Vector<Variant> binds; +	int args_bound; +	p_callable.get_bound_arguments_ref(binds, args_bound); +	if (args_bound <= 0) { +		return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, MAX(0, p_argcount + args_bound), ce); +	} else { +		Vector<const Variant *> argptrs; +		argptrs.resize(p_argcount + binds.size()); +		for (int i = 0; i < p_argcount; i++) { +			argptrs.write[i] = p_argptrs[i]; +		} +		for (int i = 0; i < binds.size(); i++) { +			argptrs.write[i + p_argcount] = &binds[i]; +		} +		return get_call_error_text(p_callable.get_object(), p_callable.get_method(), (const Variant **)argptrs.ptr(), argptrs.size(), ce); +	}  }  void Variant::register_types() { diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 6c06b63dab..05fb62ff12 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2017,6 +2017,7 @@ static void _register_variant_builtin_methods() {  	bind_method(Callable, get_object_id, sarray(), varray());  	bind_method(Callable, get_method, sarray(), varray());  	bind_method(Callable, get_bound_arguments_count, sarray(), varray()); +	bind_method(Callable, get_bound_arguments, sarray(), varray());  	bind_method(Callable, hash, sarray(), varray());  	bind_method(Callable, bindv, sarray("arguments"), varray());  	bind_method(Callable, unbind, sarray("argcount"), varray()); diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index a6fffae8b5..d1fdaef29c 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -107,6 +107,12 @@  				Calls the method represented by this [Callable]. Unlike [method call], this method expects all arguments to be contained inside the [param arguments] [Array].  			</description>  		</method> +		<method name="get_bound_arguments" qualifiers="const"> +			<return type="Array" /> +			<description> +				Return the bound arguments (as long as [method get_bound_arguments_count] is greater than zero), or empty (if [method get_bound_arguments_count] is less than or equal to zero). +			</description> +		</method>  		<method name="get_bound_arguments_count" qualifiers="const">  			<return type="int" />  			<description> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index b9f3275dfe..08964cf21d 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -780,67 +780,13 @@  		</method>  		<method name="set_drag_forwarding">  			<return type="void" /> -			<param index="0" name="target" type="Object" /> +			<param index="0" name="drag_func" type="Callable" /> +			<param index="1" name="can_drop_func" type="Callable" /> +			<param index="2" name="drop_func" type="Callable" />  			<description> -				Forwards the handling of this control's drag and drop to [param target] object. -				Forwarding can be implemented in the target object similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences: -				1. The function name must be suffixed with [b]_fw[/b] -				2. The function must take an extra argument that is the control doing the forwarding -				[codeblocks] -				[gdscript] -				# ThisControl.gd -				extends Control -				export(Control) var target_control - -				func _ready(): -				    set_drag_forwarding(target_control) - -				# TargetControl.gd -				extends Control - -				func _can_drop_data_fw(position, data, from_control): -				    return true - -				func _drop_data_fw(position, data, from_control): -				    my_handle_data(data) # Your handler method. - -				func _get_drag_data_fw(position, from_control): -				    set_drag_preview(my_preview) -				    return my_data() -				[/gdscript] -				[csharp] -				// ThisControl.cs -				public class ThisControl : Control -				{ -				    [Export] -				    public Control TargetControl { get; set; } -				    public override void _Ready() -				    { -				        SetDragForwarding(TargetControl); -				    } -				} - -				// TargetControl.cs -				public class TargetControl : Control -				{ -				    public void CanDropDataFw(Vector2 position, object data, Control fromControl) -				    { -				        return true; -				    } - -				    public void DropDataFw(Vector2 position, object data, Control fromControl) -				    { -				        MyHandleData(data); // Your handler method. -				    } - -				    public void GetDragDataFw(Vector2 position, Control fromControl) -				    { -				        SetDragPreview(MyPreview); -				        return MyData(); -				    } -				} -				[/csharp] -				[/codeblocks] +				Forwards the handling of this control's [method _get_drag_data],  [method _can_drop_data] and [method _drop_data] virtual functions to delegate callables. +				For each argument, if not empty, the delegate callable is used, otherwise the local (virtual) function is used. +				The function format for each callable should be exactly the same as the virtual functions described above.  			</description>  		</method>  		<method name="set_drag_preview"> diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml index eca6a1cbc7..a46de4c189 100644 --- a/doc/classes/PhysicsDirectBodyState2D.xml +++ b/doc/classes/PhysicsDirectBodyState2D.xml @@ -151,6 +151,13 @@  				[b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidBody2D.contact_monitor].  			</description>  		</method> +		<method name="get_contact_impulse" qualifiers="const"> +			<return type="Vector2" /> +			<param index="0" name="contact_idx" type="int" /> +			<description> +				Returns the impulse created by the contact. +			</description> +		</method>  		<method name="get_contact_local_normal" qualifiers="const">  			<return type="Vector2" />  			<param index="0" name="contact_idx" type="int" /> diff --git a/doc/classes/PhysicsDirectBodyState2DExtension.xml b/doc/classes/PhysicsDirectBodyState2DExtension.xml index 8fd34c1243..496cbf9136 100644 --- a/doc/classes/PhysicsDirectBodyState2DExtension.xml +++ b/doc/classes/PhysicsDirectBodyState2DExtension.xml @@ -130,6 +130,12 @@  			<description>  			</description>  		</method> +		<method name="_get_contact_impulse" qualifiers="virtual const"> +			<return type="Vector2" /> +			<param index="0" name="contact_idx" type="int" /> +			<description> +			</description> +		</method>  		<method name="_get_contact_local_normal" qualifiers="virtual const">  			<return type="Vector2" />  			<param index="0" name="contact_idx" type="int" /> diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 8e55f3a1c3..712b11d7d7 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -578,7 +578,7 @@ ActionMapEditor::ActionMapEditor() {  	action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed));  	main_vbox->add_child(action_tree); -	action_tree->set_drag_forwarding(this); +	action_tree->set_drag_forwarding_compat(this);  	// Adding event dialog  	event_config_dialog = memnew(InputEventConfigurationDialog); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 76d70b09e6..6e701cb6bd 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -754,7 +754,7 @@ CreateDialog::CreateDialog() {  	favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));  	favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));  	favorites->add_theme_constant_override("draw_guides", 1); -	favorites->set_drag_forwarding(this); +	favorites->set_drag_forwarding_compat(this);  	fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);  	VBoxContainer *rec_vb = memnew(VBoxContainer); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 5296749c18..7ef99d56ab 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -903,7 +903,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {  	effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));  	effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));  	effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); -	effects->set_drag_forwarding(this); +	effects->set_drag_forwarding_compat(this);  	effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));  	effects->set_allow_rmb_select(true);  	effects->set_focus_mode(FOCUS_CLICK); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index db251c857c..4001b849ff 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -935,7 +935,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {  	tree->set_select_mode(Tree::SELECT_MULTI);  	tree->set_allow_reselect(true); -	tree->set_drag_forwarding(this); +	tree->set_drag_forwarding_compat(this);  	tree->set_columns(4);  	tree->set_column_titles_visible(true); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 54d43bbf44..12aa44891d 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2065,7 +2065,7 @@ void EditorInspectorArray::_setup() {  		ae.panel = memnew(PanelContainer);  		ae.panel->set_focus_mode(FOCUS_ALL);  		ae.panel->set_mouse_filter(MOUSE_FILTER_PASS); -		ae.panel->set_drag_forwarding(this); +		ae.panel->set_drag_forwarding_compat(this);  		ae.panel->set_meta("index", begin_array_index + i);  		ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));  		ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw)); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 7aa050227d..8ef394a59f 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -569,7 +569,7 @@ EditorPropertyPath::EditorPropertyPath() {  	HBoxContainer *path_hb = memnew(HBoxContainer);  	add_child(path_hb);  	path = memnew(LineEdit); -	path->set_drag_forwarding(this); +	path->set_drag_forwarding_compat(this);  	path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);  	path_hb->add_child(path);  	path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected)); @@ -3686,7 +3686,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() {  	assign->set_h_size_flags(SIZE_EXPAND_FILL);  	assign->set_clip_text(true);  	assign->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_assign)); -	assign->set_drag_forwarding(this); +	assign->set_drag_forwarding_compat(this);  	hbc->add_child(assign);  	clear = memnew(Button); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 10f46283e6..ed667aa7c8 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -715,7 +715,7 @@ EditorPropertyArray::EditorPropertyArray() {  	edit->set_clip_text(true);  	edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));  	edit->set_toggle_mode(true); -	edit->set_drag_forwarding(this); +	edit->set_drag_forwarding_compat(this);  	edit->connect("draw", callable_mp(this, &EditorPropertyArray::_button_draw));  	add_child(edit);  	add_focusable(edit); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 94152dfd49..6b733e11f7 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -950,7 +950,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {  	assign_button->set_flat(true);  	assign_button->set_h_size_flags(SIZE_EXPAND_FILL);  	assign_button->set_clip_text(true); -	assign_button->set_drag_forwarding(this); +	assign_button->set_drag_forwarding_compat(this);  	add_child(assign_button);  	assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected));  	assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw)); diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 5985af21cd..2881302775 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -793,7 +793,7 @@ EditorSettingsDialog::EditorSettingsDialog() {  	shortcuts->connect("item_activated", callable_mp(this, &EditorSettingsDialog::_shortcut_cell_double_clicked));  	tab_shortcuts->add_child(shortcuts); -	shortcuts->set_drag_forwarding(this); +	shortcuts->set_drag_forwarding_compat(this);  	// Adding event dialog  	shortcut_editor = memnew(InputEventConfigurationDialog); diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 3e06633cc8..df5d2dcd29 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -1023,7 +1023,7 @@ ProjectExportDialog::ProjectExportDialog() {  	mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);  	presets = memnew(ItemList);  	// TODO: Must reimplement drag forwarding. -	//presets->set_drag_forwarding(this); +	//presets->set_drag_forwarding_compat(this);  	mc->add_child(presets);  	presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));  	duplicate_preset = memnew(Button); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index e66be6ce49..8306723f5c 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -3116,7 +3116,7 @@ FileSystemDock::FileSystemDock() {  	tree = memnew(Tree);  	tree->set_hide_root(true); -	tree->set_drag_forwarding(this); +	tree->set_drag_forwarding_compat(this);  	tree->set_allow_rmb_select(true);  	tree->set_select_mode(Tree::SELECT_MULTI);  	tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE)); @@ -3153,7 +3153,7 @@ FileSystemDock::FileSystemDock() {  	files = memnew(ItemList);  	files->set_v_size_flags(SIZE_EXPAND_FILL);  	files->set_select_mode(ItemList::SELECT_MULTI); -	files->set_drag_forwarding(this); +	files->set_drag_forwarding_compat(this);  	files->connect("item_clicked", callable_mp(this, &FileSystemDock::_file_list_item_clicked));  	files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));  	files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected)); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 942b6b51cf..4fe1a6c034 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4921,7 +4921,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p  	c->add_child(viewport);  	surface = memnew(Control); -	surface->set_drag_forwarding(this); +	surface->set_drag_forwarding_compat(this);  	add_child(surface);  	surface->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);  	surface->set_clip_contents(true); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 27cad1cb7e..2a5529e229 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -379,7 +379,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {  	tree->set_column_expand(1, true);  	tree->set_v_size_flags(SIZE_EXPAND_FILL); -	tree->set_drag_forwarding(this); +	tree->set_drag_forwarding_compat(this);  	vbc->add_child(tree);  	dialog = memnew(AcceptDialog); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index a23874ea05..caa42b677c 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3669,7 +3669,7 @@ ScriptEditor::ScriptEditor() {  	_sort_list_on_update = true;  	script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);  	script_list->set_allow_rmb_select(true); -	script_list->set_drag_forwarding(this); +	script_list->set_drag_forwarding_compat(this);  	context_menu = memnew(PopupMenu);  	add_child(context_menu); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 9406701ade..4d525cc5a9 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -2167,7 +2167,7 @@ ScriptTextEditor::ScriptTextEditor() {  	connection_info_dialog = memnew(ConnectionInfoDialog); -	code_editor->get_text_editor()->set_drag_forwarding(this); +	code_editor->get_text_editor()->set_drag_forwarding_compat(this);  }  ScriptTextEditor::~ScriptTextEditor() { diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index da6a1ea0af..a822584619 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -451,7 +451,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() {  	vb->add_child(shader_list);  	shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected));  	shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked)); -	shader_list->set_drag_forwarding(this); +	shader_list->set_drag_forwarding_compat(this);  	main_split->add_child(vb);  	vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 0c8fc08795..956150ec69 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -813,7 +813,7 @@ void Skeleton3DEditor::create_editors() {  	joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);  	joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);  	joint_tree->set_allow_rmb_select(true); -	joint_tree->set_drag_forwarding(this); +	joint_tree->set_drag_forwarding_compat(this);  	s_con->add_child(joint_tree);  	pose_editor = memnew(BoneTransformEditor(skeleton)); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 66892372cf..7603a5e55d 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -1408,7 +1408,7 @@ SpriteFramesEditor::SpriteFramesEditor() {  	frame_list->set_max_columns(0);  	frame_list->set_icon_mode(ItemList::ICON_MODE_TOP);  	frame_list->set_max_text_lines(2); -	frame_list->set_drag_forwarding(this); +	frame_list->set_drag_forwarding_compat(this);  	frame_list->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_frame_list_gui_input));  	frame_list->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_frame_list_item_selected)); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index f3f0542b9b..ad5881c76f 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -650,7 +650,7 @@ TextEditor::TextEditor() {  	goto_line_dialog = memnew(GotoLineDialog);  	add_child(goto_line_dialog); -	code_editor->get_text_editor()->set_drag_forwarding(this); +	code_editor->get_text_editor()->set_drag_forwarding_compat(this);  }  TextEditor::~TextEditor() { diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index e7dc5d825b..dd4daa45b7 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -2236,7 +2236,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {  	scene_tiles_list = memnew(ItemList);  	scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);  	scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); -	scene_tiles_list->set_drag_forwarding(this); +	scene_tiles_list->set_drag_forwarding_compat(this);  	scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);  	scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));  	scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked)); diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index d269a7c0ec..b44cb18dc7 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -728,7 +728,7 @@ TileSetEditor::TileSetEditor() {  	sources_list->add_user_signal(MethodInfo("sort_request"));  	sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list).bind(-1));  	sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); -	sources_list->set_drag_forwarding(this); +	sources_list->set_drag_forwarding_compat(this);  	split_container_left_side->add_child(sources_list);  	HBoxContainer *sources_bottom_actions = memnew(HBoxContainer); diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 5af338caa0..0ff8788626 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -509,7 +509,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {  	scene_tiles_list = memnew(ItemList);  	scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);  	scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL); -	scene_tiles_list->set_drag_forwarding(this); +	scene_tiles_list->set_drag_forwarding_compat(this);  	scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1));  	scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));  	scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated)); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 4cf397ffd0..46ec3bcdd1 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -4915,7 +4915,7 @@ VisualShaderEditor::VisualShaderEditor() {  	graph->set_h_size_flags(SIZE_EXPAND_FILL);  	graph->set_show_zoom_label(true);  	add_child(graph); -	graph->set_drag_forwarding(this); +	graph->set_drag_forwarding_compat(this);  	float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");  	graph->set_minimap_opacity(graph_minimap_opacity);  	float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature"); @@ -5146,7 +5146,7 @@ VisualShaderEditor::VisualShaderEditor() {  	members = memnew(Tree);  	members_vb->add_child(members); -	members->set_drag_forwarding(this); +	members->set_drag_forwarding_compat(this);  	members->set_h_size_flags(SIZE_EXPAND_FILL);  	members->set_v_size_flags(SIZE_EXPAND_FILL);  	members->set_hide_root(true); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index dad584ea92..2f50172f54 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -1415,7 +1415,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope  	add_child(tree); -	tree->set_drag_forwarding(this); +	tree->set_drag_forwarding_compat(this);  	if (p_can_rename) {  		tree->set_allow_rmb_select(true);  		tree->connect("item_mouse_selected", callable_mp(this, &SceneTreeEditor::_rmb_select)); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index e54e5e4c48..7bde4e7c4b 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2110,14 +2110,14 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig  	bool compatible = true;  	GDScriptParser::DataType op_type = assigned_value_type; -	if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { +	if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE && !op_type.is_variant()) {  		op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value);  	}  	p_assignment->set_datatype(op_type);  	// If Assignee is a variant, then you can assign anything  	// When the assigned value has a known type, further checks are possible. -	if (assignee_type.is_hard_type() && !assignee_type.is_variant() && op_type.is_hard_type()) { +	if (assignee_type.is_hard_type() && !assignee_type.is_variant() && op_type.is_hard_type() && !op_type.is_variant()) {  		if (compatible) {  			compatible = is_type_compatible(assignee_type, op_type, true, p_assignment->assigned_value);  			if (!compatible) { diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_preload_unnamed_assign_to_named.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_preload_unnamed_assign_to_named.gd index 98f1f3ec2d..81d5d59ae8 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/enum_preload_unnamed_assign_to_named.gd +++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_preload_unnamed_assign_to_named.gd @@ -1,4 +1,5 @@  enum MyEnum { VALUE_A, VALUE_B, VALUE_C = 42 } +  func test():  	const P = preload("../features/enum_value_from_parent.gd")  	var local_var: MyEnum diff --git a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd index 65c0d9dabc..200c352223 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd +++ b/modules/gdscript/tests/scripts/analyzer/errors/outer_class_lookup.gd @@ -1,12 +1,12 @@  class A: -    class B: -        func test(): -            print(A.B.D) +	class B: +		func test(): +			print(A.B.D)  class C: -    class D: -        pass +	class D: +		pass  func test(): -    var inst = A.B.new() -    inst.test() +	var inst = A.B.new() +	inst.test() diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd index 63587942f7..393b66c9f0 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd +++ b/modules/gdscript/tests/scripts/analyzer/errors/return_null_in_void_func.gd @@ -1,2 +1,2 @@  func test() -> void: -  return null +	return null diff --git a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd index 0ee4e7ea36..6be2730bab 100644 --- a/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd +++ b/modules/gdscript/tests/scripts/analyzer/errors/return_variant_in_void_func.gd @@ -1,4 +1,4 @@  func test() -> void: -  var a -  a = 1 -  return a +	var a +	a = 1 +	return a diff --git a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd index 7881a0feb6..a94487d989 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/base_outer_resolution.gd @@ -11,4 +11,3 @@ func test() -> void:  	Extend.InnerClass.InnerInnerClass.test_a_b_c(A.new(), B.new(), C.new())  	Extend.InnerClass.InnerInnerClass.test_enum(C.TestEnum.HELLO_WORLD)  	Extend.InnerClass.InnerInnerClass.test_a_prime(A.APrime.new()) - diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd index 30e7deb05a..7c846c59bd 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd @@ -1,19 +1,19 @@  class A: -    var x = 3 +	var x = 3  class B: -    var x = 4 +	var x = 4  class C: -    var x = 5 +	var x = 5  class Test: -    var a = A.new() -    var b: B = B.new() -    var c := C.new() +	var a = A.new() +	var b: B = B.new() +	var c := C.new()  func test(): -    var test_instance := Test.new() -    prints(test_instance.a.x) -    prints(test_instance.b.x) -    prints(test_instance.c.x) +	var test_instance := Test.new() +	prints(test_instance.a.x) +	prints(test_instance.b.x) +	prints(test_instance.c.x) diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd index 757744b6f1..0c740935b9 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant.gd @@ -2,5 +2,5 @@ const External = preload("external_enum_as_constant_external.notest.gd")  const MyEnum = External.MyEnum  func test(): -    print(MyEnum.WAITING == 0) -    print(MyEnum.GODOT == 1) +	print(MyEnum.WAITING == 0) +	print(MyEnum.GODOT == 1) diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd index 7c090844d0..24c1e41aab 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/external_enum_as_constant_external.notest.gd @@ -1,4 +1,4 @@  enum MyEnum { -    WAITING, -    GODOT +	WAITING, +	GODOT  } diff --git a/modules/gdscript/tests/scripts/analyzer/features/lookup_class.gd b/modules/gdscript/tests/scripts/analyzer/features/lookup_class.gd index 4a2ab7bcba..541da78332 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/lookup_class.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/lookup_class.gd @@ -1,50 +1,50 @@  # Inner-outer class lookup  class A: -    const Q: = "right one" +	const Q: = "right one"  class X: -    const Q: = "wrong one" +	const Q: = "wrong one"  class Y extends X: -    class B extends A: -        static func check() -> void: -            print(Q) +	class B extends A: +		static func check() -> void: +			print(Q)  # External class lookup  const External: = preload("lookup_class_external.notest.gd")  class Internal extends External.A: -    static func check() -> void: -        print(TARGET) +	static func check() -> void: +		print(TARGET) -    class E extends External.E: -        static func check() -> void: -            print(TARGET) -            print(WAITING) +	class E extends External.E: +		static func check() -> void: +			print(TARGET) +			print(WAITING)  # Variable lookup  class C: -    var Q := 'right one' +	var Q := 'right one'  class D: -    const Q := 'wrong one' +	const Q := 'wrong one'  class E extends D: -    class F extends C: -        func check() -> void: -            print(Q) +	class F extends C: +		func check() -> void: +			print(Q)  # Test  func test() -> void: -    # Inner-outer class lookup -    Y.B.check() -    print("---") - -    # External class lookup -    Internal.check() -    Internal.E.check() -    print("---") - -    # Variable lookup -    var f: = E.F.new() -    f.check() +	# Inner-outer class lookup +	Y.B.check() +	print("---") + +	# External class lookup +	Internal.check() +	Internal.E.check() +	print("---") + +	# Variable lookup +	var f: = E.F.new() +	f.check() diff --git a/modules/gdscript/tests/scripts/analyzer/features/lookup_signal.gd b/modules/gdscript/tests/scripts/analyzer/features/lookup_signal.gd index b19d5ee4f9..26cf6c7322 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/lookup_signal.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/lookup_signal.gd @@ -1,41 +1,41 @@  signal hello  func get_signal() -> Signal: -    return hello +	return hello  class A: -    signal hello +	signal hello -    func get_signal() -> Signal: -        return hello +	func get_signal() -> Signal: +		return hello -    class B: -        signal hello +	class B: +		signal hello -        func get_signal() -> Signal: -            return hello +		func get_signal() -> Signal: +			return hello  class C extends A.B: -    func get_signal() -> Signal: -        return hello +	func get_signal() -> Signal: +		return hello  func test(): -    var a: = A.new() -    var b: = A.B.new() -    var c: = C.new() - -    var hello_a_result: = hello == a.get_signal() -    var hello_b_result: = hello == b.get_signal() -    var hello_c_result: = hello == c.get_signal() -    var a_b_result: = a.get_signal() == b.get_signal() -    var a_c_result: = a.get_signal() == c.get_signal() -    var b_c_result: = b.get_signal() == c.get_signal() -    var c_c_result: = c.get_signal() == c.get_signal() - -    print("hello == A.hello? %s" % hello_a_result) -    print("hello == A.B.hello? %s" % hello_b_result) -    print("hello == C.hello? %s" % hello_c_result) -    print("A.hello == A.B.hello? %s" % a_b_result) -    print("A.hello == C.hello? %s" % a_c_result) -    print("A.B.hello == C.hello? %s" % b_c_result) -    print("C.hello == C.hello? %s" % c_c_result) +	var a: = A.new() +	var b: = A.B.new() +	var c: = C.new() + +	var hello_a_result: = hello == a.get_signal() +	var hello_b_result: = hello == b.get_signal() +	var hello_c_result: = hello == c.get_signal() +	var a_b_result: = a.get_signal() == b.get_signal() +	var a_c_result: = a.get_signal() == c.get_signal() +	var b_c_result: = b.get_signal() == c.get_signal() +	var c_c_result: = c.get_signal() == c.get_signal() + +	print("hello == A.hello? %s" % hello_a_result) +	print("hello == A.B.hello? %s" % hello_b_result) +	print("hello == C.hello? %s" % hello_c_result) +	print("A.hello == A.B.hello? %s" % a_b_result) +	print("A.hello == C.hello? %s" % a_c_result) +	print("A.B.hello == C.hello? %s" % b_c_result) +	print("C.hello == C.hello? %s" % c_c_result) diff --git a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd index c9caef7d7c..95f04421d1 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/return_variant_typed.gd @@ -1,5 +1,5 @@  func variant() -> Variant: -  return 'variant' +	return 'variant'  func test(): -  print(variant()) +	print(variant()) diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd index ada6030132..179e454073 100644 --- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd +++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd @@ -3,4 +3,4 @@  class_name HelloWorld  func test(): -    pass +	pass diff --git a/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd b/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd index 92dfb2366d..816783f239 100644 --- a/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd +++ b/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd @@ -1,2 +1,2 @@  func test(): -    var dictionary = { hello = "world",, } +	var dictionary = { hello = "world",, } diff --git a/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd index 4608c778aa..7a745bd995 100644 --- a/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd +++ b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd @@ -1,4 +1,4 @@  func test(): -    match 1: -        [[[var a]]], 2: -            pass +	match 1: +		[[[var a]]], 2: +			pass diff --git a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd index 43b513045b..a7197bf68f 100644 --- a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd +++ b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd @@ -1,34 +1,34 @@  func foo(x): -    match x: -        1 + 1: -            print("1+1") -        [1,2,[1,{1:2,2:var z,..}]]: -            print("[1,2,[1,{1:2,2:var z,..}]]") -            print(z) -        1 if true else 2: -            print("1 if true else 2") -        1 < 2: -            print("1 < 2") -        1 or 2 and 1: -            print("1 or 2 and 1") -        6 | 1: -            print("1 | 1") -        1 >> 1: -            print("1 >> 1") -        1, 2 or 3, 4: -            print("1, 2 or 3, 4") -        _: -            print("wildcard") +	match x: +		1 + 1: +			print("1+1") +		[1,2,[1,{1:2,2:var z,..}]]: +			print("[1,2,[1,{1:2,2:var z,..}]]") +			print(z) +		1 if true else 2: +			print("1 if true else 2") +		1 < 2: +			print("1 < 2") +		1 or 2 and 1: +			print("1 or 2 and 1") +		6 | 1: +			print("1 | 1") +		1 >> 1: +			print("1 >> 1") +		1, 2 or 3, 4: +			print("1, 2 or 3, 4") +		_: +			print("wildcard")  func test(): -    foo(6 | 1) -    foo(1 >> 1) -    foo(2) -    foo(1) -    foo(1+1) -    foo(1 < 2) -    foo([2, 1]) -    foo(4) -    foo([1, 2, [1, {1 : 2, 2:3}]]) -    foo([1, 2, [1, {1 : 2, 2:[1,3,5, "123"], 4:2}]]) -    foo([1, 2, [1, {1 : 2}]]) +	foo(6 | 1) +	foo(1 >> 1) +	foo(2) +	foo(1) +	foo(1+1) +	foo(1 < 2) +	foo([2, 1]) +	foo(4) +	foo([1, 2, [1, {1 : 2, 2:3}]]) +	foo([1, 2, [1, {1 : 2, 2:[1,3,5, "123"], 4:2}]]) +	foo([1, 2, [1, {1 : 2}]]) diff --git a/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd b/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd index 2b46f1e88a..c959c6c6af 100644 --- a/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd +++ b/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd @@ -1,27 +1,27 @@  func foo(x): -    match x: -        1: -            print("1") -        2: -            print("2") -        [1, 2]: -            print("[1, 2]") -        3 or 4: -            print("3 or 4") -        4: -            print("4") -        {1 : 2, 2 : 3}: -            print("{1 : 2, 2 : 3}") -        _: -            print("wildcard") +	match x: +		1: +			print("1") +		2: +			print("2") +		[1, 2]: +			print("[1, 2]") +		3 or 4: +			print("3 or 4") +		4: +			print("4") +		{1 : 2, 2 : 3}: +			print("{1 : 2, 2 : 3}") +		_: +			print("wildcard")  func test(): -    foo(0) -    foo(1) -    foo(2) -    foo([1, 2]) -    foo(3) -    foo(4) -    foo([4,4]) -    foo({1 : 2, 2 : 3}) -    foo({1 : 2, 4 : 3}) +	foo(0) +	foo(1) +	foo(2) +	foo([1, 2]) +	foo(3) +	foo(4) +	foo([4,4]) +	foo({1 : 2, 2 : 3}) +	foo({1 : 2, 4 : 3}) diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_callable.gd b/modules/gdscript/tests/scripts/parser/features/lambda_callable.gd index c3b2506156..17d00bce3c 100644 --- a/modules/gdscript/tests/scripts/parser/features/lambda_callable.gd +++ b/modules/gdscript/tests/scripts/parser/features/lambda_callable.gd @@ -1,4 +1,4 @@  func test(): -    var my_lambda = func(x): -        print(x) -    my_lambda.call("hello") +	var my_lambda = func(x): +		print(x) +	my_lambda.call("hello") diff --git a/modules/gdscript/tests/scripts/parser/features/match_dictionary.gd b/modules/gdscript/tests/scripts/parser/features/match_dictionary.gd index 377dd25e9e..75857fb8ff 100644 --- a/modules/gdscript/tests/scripts/parser/features/match_dictionary.gd +++ b/modules/gdscript/tests/scripts/parser/features/match_dictionary.gd @@ -1,43 +1,43 @@  func foo(x): -    match x: -        {"key1": "value1", "key2": "value2"}: -            print('{"key1": "value1", "key2": "value2"}') -        {"key1": "value1", "key2"}: -            print('{"key1": "value1", "key2"}') -        {"key1", "key2": "value2"}: -            print('{"key1", "key2": "value2"}') -        {"key1", "key2"}: -            print('{"key1", "key2"}') -        {"key1": "value1"}: -            print('{"key1": "value1"}') -        {"key1"}: -            print('{"key1"}') -        _: -            print("wildcard") +	match x: +		{"key1": "value1", "key2": "value2"}: +			print('{"key1": "value1", "key2": "value2"}') +		{"key1": "value1", "key2"}: +			print('{"key1": "value1", "key2"}') +		{"key1", "key2": "value2"}: +			print('{"key1", "key2": "value2"}') +		{"key1", "key2"}: +			print('{"key1", "key2"}') +		{"key1": "value1"}: +			print('{"key1": "value1"}') +		{"key1"}: +			print('{"key1"}') +		_: +			print("wildcard")  func bar(x): -    match x: -        {0}: -            print("0") -        {1}: -            print("1") -        {2}: -            print("2") -        _: -            print("wildcard") +	match x: +		{0}: +			print("0") +		{1}: +			print("1") +		{2}: +			print("2") +		_: +			print("wildcard")  func test(): -    foo({"key1": "value1", "key2": "value2"}) -    foo({"key1": "value1", "key2": ""}) -    foo({"key1": "", "key2": "value2"}) -    foo({"key1": "", "key2": ""}) -    foo({"key1": "value1"}) -    foo({"key1": ""}) -    foo({"key1": "value1", "key2": "value2", "key3": "value3"}) -    foo({"key1": "value1", "key3": ""}) -    foo({"key2": "value2"}) -    foo({"key3": ""}) -    bar({0: "0"}) -    bar({1: "1"}) -    bar({2: "2"}) -    bar({3: "3"}) +	foo({"key1": "value1", "key2": "value2"}) +	foo({"key1": "value1", "key2": ""}) +	foo({"key1": "", "key2": "value2"}) +	foo({"key1": "", "key2": ""}) +	foo({"key1": "value1"}) +	foo({"key1": ""}) +	foo({"key1": "value1", "key2": "value2", "key3": "value3"}) +	foo({"key1": "value1", "key3": ""}) +	foo({"key2": "value2"}) +	foo({"key3": ""}) +	bar({0: "0"}) +	bar({1: "1"}) +	bar({2: "2"}) +	bar({3: "3"}) diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd index dbe223f5f5..a278ea1154 100644 --- a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd +++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd @@ -1,26 +1,26 @@  func foo(x): -    match x: -        1, [2]: -            print('1, [2]') -        _: -            print('wildcard') +	match x: +		1, [2]: +			print('1, [2]') +		_: +			print('wildcard')  func bar(x): -    match x: -        [1], [2], [3]: -            print('[1], [2], [3]') -        [4]: -            print('[4]') -        _: -            print('wildcard') +	match x: +		[1], [2], [3]: +			print('[1], [2], [3]') +		[4]: +			print('[4]') +		_: +			print('wildcard')  func test(): -    foo(1) -    foo([2]) -    foo(2) -    bar([1]) -    bar([2]) -    bar([3]) -    bar([4]) -    bar([5]) +	foo(1) +	foo([2]) +	foo(2) +	bar([1]) +	bar([2]) +	bar([3]) +	bar([4]) +	bar([5]) diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd index a0ae7fb17c..0a71f33c25 100644 --- a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd +++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd @@ -1,6 +1,6 @@  func test(): -    match [1, 2, 3]: -        [var a, var b, var c]: -            print(a == 1) -            print(b == 2) -            print(c == 3) +	match [1, 2, 3]: +		[var a, var b, var c]: +			print(a == 1) +			print(b == 2) +			print(c == 3) diff --git a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_erase.gd b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_erase.gd index 935fb773dc..7b350e81ad 100644 --- a/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_erase.gd +++ b/modules/gdscript/tests/scripts/runtime/errors/constant_dictionary_erase.gd @@ -1,4 +1,4 @@  const dictionary := {}  func test(): -  dictionary.erase(0) +	dictionary.erase(0) diff --git a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd index 9b64084fa6..bd38259cec 100644 --- a/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd +++ b/modules/gdscript/tests/scripts/runtime/features/array_string_stringname_equivalent.gd @@ -9,7 +9,7 @@ func test():  	array_sname.push_back(&"godot")  	print("String in Array: ", "godot" in array_sname) -  # Not equal because the values are different types. +	# Not equal because the values are different types.  	print("Arrays not equal: ", array_str != array_sname)  	var string_array: Array[String] = [] diff --git a/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd b/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd index 1f15026f17..94bac1974f 100644 --- a/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd +++ b/modules/gdscript/tests/scripts/runtime/features/dictionary_string_stringname_equivalent.gd @@ -13,5 +13,5 @@ func test():  	print("String gets StringName: ", stringname_dict.get("abc"))  	stringname_dict[&"abc"] = 42 -  # They compare equal because StringName keys are converted to String. +	# They compare equal because StringName keys are converted to String.  	print("String Dictionary == StringName Dictionary: ", string_dict == stringname_dict) diff --git a/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.gd b/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.gd index f33ba7dffd..252e100bda 100644 --- a/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.gd +++ b/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.gd @@ -3,23 +3,23 @@  var a: int = 1  func shadow_regular_assignment(a: Variant, b: Variant) -> void: -  print(a) -  print(self.a) -  a = b -  print(a) -  print(self.a) +	print(a) +	print(self.a) +	a = b +	print(a) +	print(self.a)  var v := Vector2(0.0, 0.0)  func shadow_subscript_assignment(v: Vector2, x: float) -> void: -  print(v) -  print(self.v) -  v.x += x -  print(v) -  print(self.v) +	print(v) +	print(self.v) +	v.x += x +	print(v) +	print(self.v)  func test(): -  shadow_regular_assignment('a', 'b') -  shadow_subscript_assignment(Vector2(1.0, 1.0), 5.0) +	shadow_regular_assignment('a', 'b') +	shadow_subscript_assignment(Vector2(1.0, 1.0), 5.0) diff --git a/modules/gdscript/tests/scripts/runtime/features/use_conversion_assign_with_variant_value.gd b/modules/gdscript/tests/scripts/runtime/features/use_conversion_assign_with_variant_value.gd new file mode 100644 index 0000000000..af3f3cb941 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/use_conversion_assign_with_variant_value.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/71172 + +func test(): +	@warning_ignore(narrowing_conversion) +	var foo: int = 0.0 +	print(typeof(foo) == TYPE_INT) +	var dict : Dictionary = {"a":0.0} +	foo = dict.get("a") +	print(typeof(foo) == TYPE_INT) diff --git a/modules/gdscript/tests/scripts/runtime/features/use_conversion_assign_with_variant_value.out b/modules/gdscript/tests/scripts/runtime/features/use_conversion_assign_with_variant_value.out new file mode 100644 index 0000000000..9d111a8322 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/use_conversion_assign_with_variant_value.out @@ -0,0 +1,3 @@ +GDTEST_OK +true +true diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp index dbf1eecf0e..4ab41cfcb0 100644 --- a/modules/multiplayer/editor/replication_editor.cpp +++ b/modules/multiplayer/editor/replication_editor.cpp @@ -250,7 +250,7 @@ ReplicationEditor::ReplicationEditor() {  	tree->add_child(drop_label);  	drop_label->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); -	tree->set_drag_forwarding(this); +	tree->set_drag_forwarding_compat(this);  }  void ReplicationEditor::_bind_methods() { diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 944363bcb0..b5846cb692 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -642,7 +642,7 @@ inline int ColorPicker::_get_preset_size() {  void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {  	ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size));  	btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1))); -	btn_preset_new->set_drag_forwarding(this); +	btn_preset_new->set_drag_forwarding_compat(this);  	btn_preset_new->set_button_group(preset_group);  	preset_container->add_child(btn_preset_new);  	btn_preset_new->set_pressed(true); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 8460728448..6e85ae5c0e 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1813,33 +1813,53 @@ bool Control::is_focus_owner_in_shortcut_context() const {  // Drag and drop handling. -void Control::set_drag_forwarding(Object *p_target) { -	if (p_target) { -		data.drag_owner = p_target->get_instance_id(); +void Control::set_drag_forwarding_compat(Object *p_base) { +	if (p_base != nullptr) { +		data.forward_drag = Callable(p_base, "_get_drag_data_fw").bind(this); +		data.forward_can_drop = Callable(p_base, "_can_drop_data_fw").bind(this); +		data.forward_drop = Callable(p_base, "_drop_data_fw").bind(this); +  	} else { -		data.drag_owner = ObjectID(); +		data.forward_drag = Callable(); +		data.forward_can_drop = Callable(); +		data.forward_drop = Callable();  	}  } +void Control::set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop) { +	data.forward_drag = p_drag; +	data.forward_can_drop = p_can_drop; +	data.forward_drop = p_drop; +} +  Variant Control::get_drag_data(const Point2 &p_point) { -	if (data.drag_owner.is_valid()) { -		Object *obj = ObjectDB::get_instance(data.drag_owner); -		if (obj) { -			return obj->call("_get_drag_data_fw", p_point, this); +	Variant ret; +	if (data.forward_drag.is_valid()) { +		Variant p = p_point; +		const Variant *vp[1] = { &p }; +		Callable::CallError ce; +		data.forward_drag.callp((const Variant **)vp, 1, ret, ce); +		if (ce.error != Callable::CallError::CALL_OK) { +			ERR_FAIL_V_MSG(Variant(), "Error calling forwarded method from 'get_drag_data': " + Variant::get_callable_error_text(data.forward_drag, (const Variant **)vp, 1, ce) + ".");  		} +		return ret;  	} -	Variant dd; -	GDVIRTUAL_CALL(_get_drag_data, p_point, dd); -	return dd; +	GDVIRTUAL_CALL(_get_drag_data, p_point, ret); +	return ret;  }  bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const { -	if (data.drag_owner.is_valid()) { -		Object *obj = ObjectDB::get_instance(data.drag_owner); -		if (obj) { -			return obj->call("_can_drop_data_fw", p_point, p_data, this); +	if (data.forward_can_drop.is_valid()) { +		Variant ret; +		Variant p = p_point; +		const Variant *vp[2] = { &p, &p_data }; +		Callable::CallError ce; +		data.forward_can_drop.callp((const Variant **)vp, 2, ret, ce); +		if (ce.error != Callable::CallError::CALL_OK) { +			ERR_FAIL_V_MSG(Variant(), "Error calling forwarded method from 'can_drop_data': " + Variant::get_callable_error_text(data.forward_can_drop, (const Variant **)vp, 2, ce) + ".");  		} +		return ret;  	}  	bool ret = false; @@ -1848,12 +1868,16 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const  }  void Control::drop_data(const Point2 &p_point, const Variant &p_data) { -	if (data.drag_owner.is_valid()) { -		Object *obj = ObjectDB::get_instance(data.drag_owner); -		if (obj) { -			obj->call("_drop_data_fw", p_point, p_data, this); -			return; +	if (data.forward_drop.is_valid()) { +		Variant ret; +		Variant p = p_point; +		const Variant *vp[2] = { &p, &p_data }; +		Callable::CallError ce; +		data.forward_drop.callp((const Variant **)vp, 2, ret, ce); +		if (ce.error != Callable::CallError::CALL_OK) { +			ERR_FAIL_MSG("Error calling forwarded method from 'drop_data': " + Variant::get_callable_error_text(data.forward_drop, (const Variant **)vp, 2, ce) + ".");  		} +		return;  	}  	GDVIRTUAL_CALL(_drop_data, p_point, p_data); @@ -3189,7 +3213,7 @@ void Control::_bind_methods() {  	ClassDB::bind_method(D_METHOD("grab_click_focus"), &Control::grab_click_focus); -	ClassDB::bind_method(D_METHOD("set_drag_forwarding", "target"), &Control::set_drag_forwarding); +	ClassDB::bind_method(D_METHOD("set_drag_forwarding", "drag_func", "can_drop_func", "drop_func"), &Control::set_drag_forwarding);  	ClassDB::bind_method(D_METHOD("set_drag_preview", "control"), &Control::set_drag_preview);  	ClassDB::bind_method(D_METHOD("is_drag_successful"), &Control::is_drag_successful); diff --git a/scene/gui/control.h b/scene/gui/control.h index 9705dd62db..52efe42bd5 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -168,7 +168,9 @@ private:  		Control *parent_control = nullptr;  		Window *parent_window = nullptr;  		CanvasItem *parent_canvas_item = nullptr; -		ObjectID drag_owner; +		Callable forward_drag; +		Callable forward_can_drop; +		Callable forward_drop;  		// Positioning and sizing. @@ -499,7 +501,8 @@ public:  	// Drag and drop handling. -	virtual void set_drag_forwarding(Object *p_target); +	virtual void set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop); +	virtual void set_drag_forwarding_compat(Object *p_base);  	virtual Variant get_drag_data(const Point2 &p_point);  	virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;  	virtual void drop_data(const Point2 &p_point, const Variant &p_data); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index cd1ebba5d1..3457cfa94f 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -975,7 +975,7 @@ void TabContainer::_bind_methods() {  TabContainer::TabContainer() {  	tab_bar = memnew(TabBar); -	tab_bar->set_drag_forwarding(this); +	tab_bar->set_drag_forwarding_compat(this);  	add_child(tab_bar, false, INTERNAL_MODE_FRONT);  	tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);  	tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed)); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index e76abe57ba..3458b87b8d 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -4850,7 +4850,11 @@ void Tree::_do_incr_search(const String &p_add) {  		return;  	} -	item->select(col); +	if (select_mode == SELECT_MULTI) { +		item->set_as_cursor(col); +	} else { +		item->select(col); +	}  	ensure_cursor_is_visible();  } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index d80a4004a4..80b9ff3f38 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -601,14 +601,14 @@ Error ResourceLoaderText::load() {  		resource_current++; +		if (progress && resources_total > 0) { +			*progress = resource_current / float(resources_total); +		} +  		int_resources[id] = res; //always assign int resources -		if (do_assign) { -			if (cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE) { -				res->set_path(path); -			} else { -				res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); -				res->set_scene_unique_id(id); -			} +		if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { +			res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); +			res->set_scene_unique_id(id);  		}  		Dictionary missing_resource_properties; @@ -663,10 +663,6 @@ Error ResourceLoaderText::load() {  		if (!missing_resource_properties.is_empty()) {  			res->set_meta(META_MISSING_RESOURCES, missing_resource_properties);  		} - -		if (progress && resources_total > 0) { -			*progress = resource_current / float(resources_total); -		}  	}  	while (true) { @@ -716,8 +712,6 @@ Error ResourceLoaderText::load() {  			resource = Ref<Resource>(r);  		} -		resource_current++; -  		Dictionary missing_resource_properties;  		while (true) { @@ -770,6 +764,12 @@ Error ResourceLoaderText::load() {  			}  		} +		resource_current++; + +		if (progress && resources_total > 0) { +			*progress = resource_current / float(resources_total); +		} +  		if (missing_resource) {  			missing_resource->set_recording_properties(false);  		} @@ -779,9 +779,6 @@ Error ResourceLoaderText::load() {  		}  		error = OK; -		if (progress && resources_total > 0) { -			*progress = resource_current / float(resources_total); -		}  		return error;  	} diff --git a/servers/extensions/physics_server_2d_extension.cpp b/servers/extensions/physics_server_2d_extension.cpp index a0c082ee44..a174ceadac 100644 --- a/servers/extensions/physics_server_2d_extension.cpp +++ b/servers/extensions/physics_server_2d_extension.cpp @@ -101,6 +101,7 @@ void PhysicsDirectBodyState2DExtension::_bind_methods() {  	GDVIRTUAL_BIND(_get_contact_collider_object, "contact_idx");  	GDVIRTUAL_BIND(_get_contact_collider_shape, "contact_idx");  	GDVIRTUAL_BIND(_get_contact_collider_velocity_at_position, "contact_idx"); +	GDVIRTUAL_BIND(_get_contact_impulse, "contact_idx");  	GDVIRTUAL_BIND(_get_step);  	GDVIRTUAL_BIND(_integrate_forces); diff --git a/servers/extensions/physics_server_2d_extension.h b/servers/extensions/physics_server_2d_extension.h index c4970f6398..0008653f66 100644 --- a/servers/extensions/physics_server_2d_extension.h +++ b/servers/extensions/physics_server_2d_extension.h @@ -100,6 +100,7 @@ public:  	EXBIND1RC(Object *, get_contact_collider_object, int)  	EXBIND1RC(int, get_contact_collider_shape, int)  	EXBIND1RC(Vector2, get_contact_collider_velocity_at_position, int) +	EXBIND1RC(Vector2, get_contact_impulse, int)  	EXBIND0RC(real_t, get_step)  	EXBIND0(integrate_forces) diff --git a/servers/physics_2d/godot_body_2d.h b/servers/physics_2d/godot_body_2d.h index 34da64dac9..71dc826604 100644 --- a/servers/physics_2d/godot_body_2d.h +++ b/servers/physics_2d/godot_body_2d.h @@ -132,6 +132,7 @@ class GodotBody2D : public GodotCollisionObject2D {  		ObjectID collider_instance_id;  		RID collider;  		Vector2 collider_velocity_at_pos; +		Vector2 impulse;  	};  	Vector<Contact> contacts; //no contacts by default @@ -190,7 +191,7 @@ public:  	_FORCE_INLINE_ int get_max_contacts_reported() const { return contacts.size(); }  	_FORCE_INLINE_ bool can_report_contacts() const { return !contacts.is_empty(); } -	_FORCE_INLINE_ void add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos); +	_FORCE_INLINE_ void add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos, const Vector2 &p_impulse);  	_FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); }  	_FORCE_INLINE_ void remove_exception(const RID &p_exception) { exceptions.erase(p_exception); } @@ -340,7 +341,7 @@ public:  //add contact inline -void GodotBody2D::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos) { +void GodotBody2D::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos, const Vector2 &p_impulse) {  	int c_max = contacts.size();  	if (c_max == 0) { @@ -380,6 +381,7 @@ void GodotBody2D::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local  	c[idx].collider_instance_id = p_collider_instance_id;  	c[idx].collider = p_collider;  	c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos; +	c[idx].impulse = p_impulse;  }  #endif // GODOT_BODY_2D_H diff --git a/servers/physics_2d/godot_body_direct_state_2d.cpp b/servers/physics_2d/godot_body_direct_state_2d.cpp index 35092b631a..2fa933ce17 100644 --- a/servers/physics_2d/godot_body_direct_state_2d.cpp +++ b/servers/physics_2d/godot_body_direct_state_2d.cpp @@ -210,6 +210,11 @@ Vector2 GodotPhysicsDirectBodyState2D::get_contact_collider_velocity_at_position  	return body->contacts[p_contact_idx].collider_velocity_at_pos;  } +Vector2 GodotPhysicsDirectBodyState2D::get_contact_impulse(int p_contact_idx) const { +	ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2()); +	return body->contacts[p_contact_idx].impulse; +} +  PhysicsDirectSpaceState2D *GodotPhysicsDirectBodyState2D::get_space_state() {  	return body->get_space()->get_direct_state();  } diff --git a/servers/physics_2d/godot_body_direct_state_2d.h b/servers/physics_2d/godot_body_direct_state_2d.h index c01ee62920..545d52ad23 100644 --- a/servers/physics_2d/godot_body_direct_state_2d.h +++ b/servers/physics_2d/godot_body_direct_state_2d.h @@ -92,8 +92,8 @@ public:  	virtual Vector2 get_contact_collider_position(int p_contact_idx) const override;  	virtual ObjectID get_contact_collider_id(int p_contact_idx) const override;  	virtual int get_contact_collider_shape(int p_contact_idx) const override; -  	virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const override; +	virtual Vector2 get_contact_impulse(int p_contact_idx) const override;  	virtual PhysicsDirectSpaceState2D *get_space_state() override; diff --git a/servers/physics_2d/godot_body_pair_2d.cpp b/servers/physics_2d/godot_body_pair_2d.cpp index 474367def0..40dbb4fcf4 100644 --- a/servers/physics_2d/godot_body_pair_2d.cpp +++ b/servers/physics_2d/godot_body_pair_2d.cpp @@ -434,21 +434,6 @@ bool GodotBodyPair2D::pre_solve(real_t p_step) {  		c.rA = global_A - A->get_center_of_mass();  		c.rB = global_B - B->get_center_of_mass() - offset_B; -		if (A->can_report_contacts()) { -			Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x); -			A->add_contact(global_A + offset_A, -c.normal, depth, shape_A, global_B + offset_A, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity()); -		} - -		if (B->can_report_contacts()) { -			Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x); -			B->add_contact(global_B + offset_A, c.normal, depth, shape_B, global_A + offset_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity()); -		} - -		if (report_contacts_only) { -			collided = false; -			continue; -		} -  		// Precompute normal mass, tangent mass, and bias.  		real_t rnA = c.rA.dot(c.normal);  		real_t rnB = c.rB.dot(c.normal); @@ -466,11 +451,28 @@ bool GodotBodyPair2D::pre_solve(real_t p_step) {  		c.bias = -bias * inv_dt * MIN(0.0f, -depth + max_penetration);  		c.depth = depth; +		Vector2 P = c.acc_normal_impulse * c.normal + c.acc_tangent_impulse * tangent; + +		c.acc_impulse -= P; + +		if (A->can_report_contacts()) { +			Vector2 crB(-B->get_angular_velocity() * c.rB.y, B->get_angular_velocity() * c.rB.x); +			A->add_contact(global_A + offset_A, -c.normal, depth, shape_A, global_B + offset_A, shape_B, B->get_instance_id(), B->get_self(), crB + B->get_linear_velocity(), c.acc_impulse); +		} + +		if (B->can_report_contacts()) { +			Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x); +			B->add_contact(global_B + offset_A, c.normal, depth, shape_B, global_A + offset_A, shape_A, A->get_instance_id(), A->get_self(), crA + A->get_linear_velocity(), c.acc_impulse); +		} + +		if (report_contacts_only) { +			collided = false; +			continue; +		} +  #ifdef ACCUMULATE_IMPULSES  		{  			// Apply normal + friction impulse -			Vector2 P = c.acc_normal_impulse * c.normal + c.acc_tangent_impulse * tangent; -  			if (collide_A) {  				A->apply_impulse(-P, c.rA + A->get_center_of_mass());  			} @@ -581,6 +583,7 @@ void GodotBodyPair2D::solve(real_t p_step) {  		if (collide_B) {  			B->apply_impulse(j, c.rB + B->get_center_of_mass());  		} +		c.acc_impulse -= j;  	}  } diff --git a/servers/physics_2d/godot_body_pair_2d.h b/servers/physics_2d/godot_body_pair_2d.h index 7e7a9839c1..4e9bfa6022 100644 --- a/servers/physics_2d/godot_body_pair_2d.h +++ b/servers/physics_2d/godot_body_pair_2d.h @@ -59,6 +59,7 @@ class GodotBodyPair2D : public GodotConstraint2D {  		Vector2 position;  		Vector2 normal;  		Vector2 local_A, local_B; +		Vector2 acc_impulse; // accumulated impulse  		real_t acc_normal_impulse = 0.0; // accumulated normal impulse (Pn)  		real_t acc_tangent_impulse = 0.0; // accumulated tangent impulse (Pt)  		real_t acc_bias_impulse = 0.0; // accumulated normal impulse for position bias (Pnb) diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 4973b9970a..214de27b35 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -126,6 +126,7 @@ void PhysicsDirectBodyState2D::_bind_methods() {  	ClassDB::bind_method(D_METHOD("get_contact_collider_object", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_object);  	ClassDB::bind_method(D_METHOD("get_contact_collider_shape", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_shape);  	ClassDB::bind_method(D_METHOD("get_contact_collider_velocity_at_position", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_velocity_at_position); +	ClassDB::bind_method(D_METHOD("get_contact_impulse", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_impulse);  	ClassDB::bind_method(D_METHOD("get_step"), &PhysicsDirectBodyState2D::get_step);  	ClassDB::bind_method(D_METHOD("integrate_forces"), &PhysicsDirectBodyState2D::integrate_forces);  	ClassDB::bind_method(D_METHOD("get_space_state"), &PhysicsDirectBodyState2D::get_space_state); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index aac4d9d69e..836ab5bd76 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -99,6 +99,7 @@ public:  	virtual Object *get_contact_collider_object(int p_contact_idx) const;  	virtual int get_contact_collider_shape(int p_contact_idx) const = 0;  	virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const = 0; +	virtual Vector2 get_contact_impulse(int p_contact_idx) const = 0;  	virtual real_t get_step() const = 0;  	virtual void integrate_forces(); diff --git a/servers/rendering/renderer_rd/effects/luminance.cpp b/servers/rendering/renderer_rd/effects/luminance.cpp new file mode 100644 index 0000000000..7462282932 --- /dev/null +++ b/servers/rendering/renderer_rd/effects/luminance.cpp @@ -0,0 +1,255 @@ +/**************************************************************************/ +/*  luminance.cpp                                                         */ +/**************************************************************************/ +/*                         This file is part of:                          */ +/*                             GODOT ENGINE                               */ +/*                        https://godotengine.org                         */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ +/*                                                                        */ +/* Permission is hereby granted, free of charge, to any person obtaining  */ +/* a copy of this software and associated documentation files (the        */ +/* "Software"), to deal in the Software without restriction, including    */ +/* without limitation the rights to use, copy, modify, merge, publish,    */ +/* distribute, sublicense, and/or sell copies of the Software, and to     */ +/* permit persons to whom the Software is furnished to do so, subject to  */ +/* the following conditions:                                              */ +/*                                                                        */ +/* The above copyright notice and this permission notice shall be         */ +/* included in all copies or substantial portions of the Software.        */ +/*                                                                        */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ +/**************************************************************************/ + +#include "luminance.h" +#include "../framebuffer_cache_rd.h" +#include "../uniform_set_cache_rd.h" +#include "servers/rendering/renderer_rd/storage_rd/material_storage.h" + +using namespace RendererRD; + +Luminance::Luminance(bool p_prefer_raster_effects) { +	prefer_raster_effects = p_prefer_raster_effects; + +	if (prefer_raster_effects) { +		Vector<String> luminance_reduce_modes; +		luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST +		luminance_reduce_modes.push_back("\n"); // LUMINANCE_REDUCE_FRAGMENT +		luminance_reduce_modes.push_back("\n#define FINAL_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FINAL + +		luminance_reduce_raster.shader.initialize(luminance_reduce_modes); +		luminance_reduce_raster.shader_version = luminance_reduce_raster.shader.version_create(); + +		for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) { +			luminance_reduce_raster.pipelines[i].setup(luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); +		} +	} else { +		// Initialize luminance_reduce +		Vector<String> luminance_reduce_modes; +		luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n"); +		luminance_reduce_modes.push_back("\n"); +		luminance_reduce_modes.push_back("\n#define WRITE_LUMINANCE\n"); + +		luminance_reduce.shader.initialize(luminance_reduce_modes); +		luminance_reduce.shader_version = luminance_reduce.shader.version_create(); + +		for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) { +			luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i)); +		} + +		for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) { +			luminance_reduce_raster.pipelines[i].clear(); +		} +	} +} + +Luminance::~Luminance() { +	if (prefer_raster_effects) { +		luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version); +	} else { +		luminance_reduce.shader.version_free(luminance_reduce.shader_version); +	} +} + +void Luminance::LuminanceBuffers::set_prefer_raster_effects(bool p_prefer_raster_effects) { +	prefer_raster_effects = p_prefer_raster_effects; +} + +void Luminance::LuminanceBuffers::configure(RenderSceneBuffersRD *p_render_buffers) { +	Size2i internal_size = p_render_buffers->get_internal_size(); +	int w = internal_size.x; +	int h = internal_size.y; + +	while (true) { +		w = MAX(w / 8, 1); +		h = MAX(h / 8, 1); + +		RD::TextureFormat tf; +		tf.format = RD::DATA_FORMAT_R32_SFLOAT; +		tf.width = w; +		tf.height = h; + +		bool final = w == 1 && h == 1; + +		if (prefer_raster_effects) { +			tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; +		} else { +			tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; +			if (final) { +				tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; +			} +		} + +		RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); +		reduce.push_back(texture); + +		if (final) { +			current = RD::get_singleton()->texture_create(tf, RD::TextureView()); +			break; +		} +	} +} + +void Luminance::LuminanceBuffers::free_data() { +	for (int i = 0; i < reduce.size(); i++) { +		RD::get_singleton()->free(reduce[i]); +	} +	reduce.clear(); + +	if (current.is_valid()) { +		RD::get_singleton()->free(current); +		current = RID(); +	} +} + +Ref<Luminance::LuminanceBuffers> Luminance::get_luminance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers) { +	if (p_render_buffers->has_custom_data(RB_LUMINANCE_BUFFERS)) { +		return p_render_buffers->get_custom_data(RB_LUMINANCE_BUFFERS); +	} + +	Ref<LuminanceBuffers> buffers; +	buffers.instantiate(); +	buffers->set_prefer_raster_effects(prefer_raster_effects); +	buffers->configure(p_render_buffers.ptr()); + +	p_render_buffers->set_custom_data(RB_LUMINANCE_BUFFERS, buffers); + +	return buffers; +} + +RID Luminance::get_current_luminance_buffer(Ref<RenderSceneBuffersRD> p_render_buffers) { +	if (p_render_buffers->has_custom_data(RB_LUMINANCE_BUFFERS)) { +		Ref<LuminanceBuffers> buffers = p_render_buffers->get_custom_data(RB_LUMINANCE_BUFFERS); +		return buffers->current; +	} + +	return RID(); +} + +void Luminance::luminance_reduction(RID p_source_texture, const Size2i p_source_size, Ref<LuminanceBuffers> p_luminance_buffers, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { +	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); +	ERR_FAIL_NULL(uniform_set_cache); +	MaterialStorage *material_storage = MaterialStorage::get_singleton(); +	ERR_FAIL_NULL(material_storage); + +	// setup our uniforms +	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + +	if (prefer_raster_effects) { +		LuminanceReduceRasterPushConstant push_constant; +		memset(&push_constant, 0, sizeof(LuminanceReduceRasterPushConstant)); + +		push_constant.max_luminance = p_max_luminance; +		push_constant.min_luminance = p_min_luminance; +		push_constant.exposure_adjust = p_adjust; + +		for (int i = 0; i < p_luminance_buffers->reduce.size(); i++) { +			push_constant.source_size[0] = i == 0 ? p_source_size.x : push_constant.dest_size[0]; +			push_constant.source_size[1] = i == 0 ? p_source_size.y : push_constant.dest_size[1]; +			push_constant.dest_size[0] = MAX(push_constant.source_size[0] / 8, 1); +			push_constant.dest_size[1] = MAX(push_constant.source_size[1] / 8, 1); + +			bool final = !p_set && (push_constant.dest_size[0] == 1) && (push_constant.dest_size[1] == 1); +			LuminanceReduceRasterMode mode = final ? LUMINANCE_REDUCE_FRAGMENT_FINAL : (i == 0 ? LUMINANCE_REDUCE_FRAGMENT_FIRST : LUMINANCE_REDUCE_FRAGMENT); +			RID shader = luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, mode); + +			RID framebuffer = FramebufferCacheRD::get_singleton()->get_cache(p_luminance_buffers->reduce[i]); + +			RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, i == 0 ? p_source_texture : p_luminance_buffers->reduce[i - 1] })); + +			RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); +			RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(framebuffer))); +			RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0); +			if (final) { +				RD::Uniform u_current_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_luminance_buffers->current })); +				RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_current_texture), 1); +			} +			RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); + +			RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(LuminanceReduceRasterPushConstant)); + +			RD::get_singleton()->draw_list_draw(draw_list, true); +			RD::get_singleton()->draw_list_end(); +		} +	} else { +		LuminanceReducePushConstant push_constant; +		memset(&push_constant, 0, sizeof(LuminanceReducePushConstant)); + +		push_constant.source_size[0] = p_source_size.x; +		push_constant.source_size[1] = p_source_size.y; +		push_constant.max_luminance = p_max_luminance; +		push_constant.min_luminance = p_min_luminance; +		push_constant.exposure_adjust = p_adjust; + +		RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + +		for (int i = 0; i < p_luminance_buffers->reduce.size(); i++) { +			RID shader; + +			if (i == 0) { +				shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE_READ); +				RD::Uniform u_source_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_texture })); + +				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_READ]); +				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0); +			} else { +				RD::get_singleton()->compute_list_add_barrier(compute_list); //needs barrier, wait until previous is done + +				if (i == p_luminance_buffers->reduce.size() - 1 && !p_set) { +					shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE_WRITE); +					RD::Uniform u_current_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_luminance_buffers->current })); + +					RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_WRITE]); +					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_current_texture), 2); +				} else { +					shader = luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, LUMINANCE_REDUCE); +					RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE]); +				} + +				RD::Uniform u_source_texture(RD::UNIFORM_TYPE_IMAGE, 0, p_luminance_buffers->reduce[i - 1]); +				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_texture), 0); +			} + +			RD::Uniform u_reduce_texture(RD::UNIFORM_TYPE_IMAGE, 0, p_luminance_buffers->reduce[i]); +			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_reduce_texture), 1); + +			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(LuminanceReducePushConstant)); + +			RD::get_singleton()->compute_list_dispatch_threads(compute_list, push_constant.source_size[0], push_constant.source_size[1], 1); + +			push_constant.source_size[0] = MAX(push_constant.source_size[0] / 8, 1); +			push_constant.source_size[1] = MAX(push_constant.source_size[1] / 8, 1); +		} + +		RD::get_singleton()->compute_list_end(); +	} + +	SWAP(p_luminance_buffers->current, p_luminance_buffers->reduce.write[p_luminance_buffers->reduce.size() - 1]); +} diff --git a/servers/rendering/renderer_rd/effects/luminance.h b/servers/rendering/renderer_rd/effects/luminance.h new file mode 100644 index 0000000000..0f343fceab --- /dev/null +++ b/servers/rendering/renderer_rd/effects/luminance.h @@ -0,0 +1,120 @@ +/**************************************************************************/ +/*  luminance.h                                                           */ +/**************************************************************************/ +/*                         This file is part of:                          */ +/*                             GODOT ENGINE                               */ +/*                        https://godotengine.org                         */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ +/*                                                                        */ +/* Permission is hereby granted, free of charge, to any person obtaining  */ +/* a copy of this software and associated documentation files (the        */ +/* "Software"), to deal in the Software without restriction, including    */ +/* without limitation the rights to use, copy, modify, merge, publish,    */ +/* distribute, sublicense, and/or sell copies of the Software, and to     */ +/* permit persons to whom the Software is furnished to do so, subject to  */ +/* the following conditions:                                              */ +/*                                                                        */ +/* The above copyright notice and this permission notice shall be         */ +/* included in all copies or substantial portions of the Software.        */ +/*                                                                        */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ +/**************************************************************************/ + +#ifndef LUMINANCE_RD_H +#define LUMINANCE_RD_H + +#include "servers/rendering/renderer_rd/pipeline_cache_rd.h" +#include "servers/rendering/renderer_rd/shaders/effects/luminance_reduce.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h" +#include "servers/rendering/renderer_scene_render.h" + +#include "servers/rendering_server.h" + +#define RB_LUMINANCE_BUFFERS SNAME("luminance_buffers") + +namespace RendererRD { + +class Luminance { +private: +	bool prefer_raster_effects; + +	enum LuminanceReduceMode { +		LUMINANCE_REDUCE_READ, +		LUMINANCE_REDUCE, +		LUMINANCE_REDUCE_WRITE, +		LUMINANCE_REDUCE_MAX +	}; + +	struct LuminanceReducePushConstant { +		int32_t source_size[2]; +		float max_luminance; +		float min_luminance; +		float exposure_adjust; +		float pad[3]; +	}; + +	struct LuminanceReduce { +		LuminanceReduceShaderRD shader; +		RID shader_version; +		RID pipelines[LUMINANCE_REDUCE_MAX]; +	} luminance_reduce; + +	enum LuminanceReduceRasterMode { +		LUMINANCE_REDUCE_FRAGMENT_FIRST, +		LUMINANCE_REDUCE_FRAGMENT, +		LUMINANCE_REDUCE_FRAGMENT_FINAL, +		LUMINANCE_REDUCE_FRAGMENT_MAX +	}; + +	struct LuminanceReduceRasterPushConstant { +		int32_t source_size[2]; +		int32_t dest_size[2]; +		float exposure_adjust; +		float min_luminance; +		float max_luminance; +		uint32_t pad1; +	}; + +	struct LuminanceReduceFragment { +		LuminanceReduceRasterShaderRD shader; +		RID shader_version; +		PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX]; +	} luminance_reduce_raster; + +public: +	class LuminanceBuffers : public RenderBufferCustomDataRD { +		GDCLASS(LuminanceBuffers, RenderBufferCustomDataRD); + +	private: +		bool prefer_raster_effects; + +	public: +		Vector<RID> reduce; +		RID current; + +		virtual void configure(RenderSceneBuffersRD *p_render_buffers) override; +		virtual void free_data() override; + +		void set_prefer_raster_effects(bool p_prefer_raster_effects); +	}; + +	Ref<LuminanceBuffers> get_luminance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers); +	RID get_current_luminance_buffer(Ref<RenderSceneBuffersRD> p_render_buffers); +	void luminance_reduction(RID p_source_texture, const Size2i p_source_size, Ref<LuminanceBuffers> p_luminance_buffers, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); + +	Luminance(bool p_prefer_raster_effects); +	~Luminance(); +}; + +} // namespace RendererRD + +#endif // LUMINANCE_RD_H diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 6d15d5c77b..b7a1396f9c 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -55,36 +55,13 @@ RID EffectsRD::_get_uniform_set_from_image(RID p_image) {  	u.append_id(p_image);  	uniforms.push_back(u);  	//any thing with the same configuration (one texture in binding 0 for set 0), is good -	RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, 0), 1); +	RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0), 1);  	image_to_uniform_set_cache[p_image] = uniform_set;  	return uniform_set;  } -RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { -	if (texture_to_uniform_set_cache.has(p_texture)) { -		RID uniform_set = texture_to_uniform_set_cache[p_texture]; -		if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { -			return uniform_set; -		} -	} - -	Vector<RD::Uniform> uniforms; -	RD::Uniform u; -	u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; -	u.binding = 0; -	u.append_id(p_use_mipmaps ? default_mipmap_sampler : default_sampler); -	u.append_id(p_texture); -	uniforms.push_back(u); -	// anything with the same configuration (one texture in binding 0 for set 0), is good -	RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, 0), 0); - -	texture_to_uniform_set_cache[p_texture] = uniform_set; - -	return uniform_set; -} -  RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) {  	if (texture_to_compute_uniform_set_cache.has(p_texture)) {  		RID uniform_set = texture_to_compute_uniform_set_cache[p_texture]; @@ -101,86 +78,13 @@ RID EffectsRD::_get_compute_uniform_set_from_texture(RID p_texture, bool p_use_m  	u.append_id(p_texture);  	uniforms.push_back(u);  	//any thing with the same configuration (one texture in binding 0 for set 0), is good -	RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, 0), 0); +	RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0), 0);  	texture_to_compute_uniform_set_cache[p_texture] = uniform_set;  	return uniform_set;  } -void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { -	ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer."); - -	luminance_reduce.push_constant.source_size[0] = p_source_size.x; -	luminance_reduce.push_constant.source_size[1] = p_source_size.y; -	luminance_reduce.push_constant.max_luminance = p_max_luminance; -	luminance_reduce.push_constant.min_luminance = p_min_luminance; -	luminance_reduce.push_constant.exposure_adjust = p_adjust; - -	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - -	for (int i = 0; i < p_reduce.size(); i++) { -		if (i == 0) { -			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_READ]); -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_texture), 0); -		} else { -			RD::get_singleton()->compute_list_add_barrier(compute_list); //needs barrier, wait until previous is done - -			if (i == p_reduce.size() - 1 && !p_set) { -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE_WRITE]); -				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_prev_luminance), 2); -			} else { -				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, luminance_reduce.pipelines[LUMINANCE_REDUCE]); -			} - -			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_reduce[i - 1]), 0); -		} - -		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_reduce[i]), 1); - -		RD::get_singleton()->compute_list_set_push_constant(compute_list, &luminance_reduce.push_constant, sizeof(LuminanceReducePushConstant)); - -		RD::get_singleton()->compute_list_dispatch_threads(compute_list, luminance_reduce.push_constant.source_size[0], luminance_reduce.push_constant.source_size[1], 1); - -		luminance_reduce.push_constant.source_size[0] = MAX(luminance_reduce.push_constant.source_size[0] / 8, 1); -		luminance_reduce.push_constant.source_size[1] = MAX(luminance_reduce.push_constant.source_size[1] / 8, 1); -	} - -	RD::get_singleton()->compute_list_end(); -} - -void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { -	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster version of luminance reduction with the clustered renderer."); -	ERR_FAIL_COND_MSG(p_reduce.size() != p_fb.size(), "Incorrect frame buffer account for luminance reduction."); - -	luminance_reduce_raster.push_constant.max_luminance = p_max_luminance; -	luminance_reduce_raster.push_constant.min_luminance = p_min_luminance; -	luminance_reduce_raster.push_constant.exposure_adjust = p_adjust; - -	for (int i = 0; i < p_reduce.size(); i++) { -		luminance_reduce_raster.push_constant.source_size[0] = i == 0 ? p_source_size.x : luminance_reduce_raster.push_constant.dest_size[0]; -		luminance_reduce_raster.push_constant.source_size[1] = i == 0 ? p_source_size.y : luminance_reduce_raster.push_constant.dest_size[1]; -		luminance_reduce_raster.push_constant.dest_size[0] = MAX(luminance_reduce_raster.push_constant.source_size[0] / 8, 1); -		luminance_reduce_raster.push_constant.dest_size[1] = MAX(luminance_reduce_raster.push_constant.source_size[1] / 8, 1); - -		bool final = !p_set && (luminance_reduce_raster.push_constant.dest_size[0] == 1) && (luminance_reduce_raster.push_constant.dest_size[1] == 1); -		LuminanceReduceRasterMode mode = final ? LUMINANCE_REDUCE_FRAGMENT_FINAL : (i == 0 ? LUMINANCE_REDUCE_FRAGMENT_FIRST : LUMINANCE_REDUCE_FRAGMENT); - -		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); -		RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, luminance_reduce_raster.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_fb[i]))); -		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(i == 0 ? p_source_texture : p_reduce[i - 1]), 0); -		if (final) { -			RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_prev_luminance), 1); -		} -		RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - -		RD::get_singleton()->draw_list_set_push_constant(draw_list, &luminance_reduce_raster.push_constant, sizeof(LuminanceReduceRasterPushConstant)); - -		RD::get_singleton()->draw_list_draw(draw_list, true); -		RD::get_singleton()->draw_list_end(); -	} -} -  void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve) {  	roughness_limiter.push_constant.screen_size[0] = p_size.x;  	roughness_limiter.push_constant.screen_size[1] = p_size.y; @@ -270,39 +174,6 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) {  EffectsRD::EffectsRD(bool p_prefer_raster_effects) {  	prefer_raster_effects = p_prefer_raster_effects; -	if (prefer_raster_effects) { -		Vector<String> luminance_reduce_modes; -		luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST -		luminance_reduce_modes.push_back("\n"); // LUMINANCE_REDUCE_FRAGMENT -		luminance_reduce_modes.push_back("\n#define FINAL_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FINAL - -		luminance_reduce_raster.shader.initialize(luminance_reduce_modes); -		memset(&luminance_reduce_raster.push_constant, 0, sizeof(LuminanceReduceRasterPushConstant)); -		luminance_reduce_raster.shader_version = luminance_reduce_raster.shader.version_create(); - -		for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) { -			luminance_reduce_raster.pipelines[i].setup(luminance_reduce_raster.shader.version_get_shader(luminance_reduce_raster.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); -		} -	} else { -		// Initialize luminance_reduce -		Vector<String> luminance_reduce_modes; -		luminance_reduce_modes.push_back("\n#define READ_TEXTURE\n"); -		luminance_reduce_modes.push_back("\n"); -		luminance_reduce_modes.push_back("\n#define WRITE_LUMINANCE\n"); - -		luminance_reduce.shader.initialize(luminance_reduce_modes); - -		luminance_reduce.shader_version = luminance_reduce.shader.version_create(); - -		for (int i = 0; i < LUMINANCE_REDUCE_MAX; i++) { -			luminance_reduce.pipelines[i] = RD::get_singleton()->compute_pipeline_create(luminance_reduce.shader.version_get_shader(luminance_reduce.shader_version, i)); -		} - -		for (int i = 0; i < LUMINANCE_REDUCE_FRAGMENT_MAX; i++) { -			luminance_reduce_raster.pipelines[i].clear(); -		} -	} -  	if (!prefer_raster_effects) {  		// Initialize roughness limiter  		Vector<String> shader_modes; @@ -368,11 +239,6 @@ EffectsRD::~EffectsRD() {  	RD::get_singleton()->free(default_mipmap_sampler);  	RD::get_singleton()->free(index_buffer); //array gets freed as dependency -	if (prefer_raster_effects) { -		luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version); -	} else { -		luminance_reduce.shader.version_free(luminance_reduce.shader_version); -	}  	if (!prefer_raster_effects) {  		roughness_limiter.shader.version_free(roughness_limiter.shader_version);  	} diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index bbe240b241..45198e5fc5 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -33,8 +33,6 @@  #include "core/math/projection.h"  #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" -#include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"  #include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h"  #include "servers/rendering/renderer_rd/shaders/sort.glsl.gen.h"  #include "servers/rendering/renderer_scene_render.h" @@ -45,51 +43,6 @@ class EffectsRD {  private:  	bool prefer_raster_effects; -	enum LuminanceReduceMode { -		LUMINANCE_REDUCE_READ, -		LUMINANCE_REDUCE, -		LUMINANCE_REDUCE_WRITE, -		LUMINANCE_REDUCE_MAX -	}; - -	struct LuminanceReducePushConstant { -		int32_t source_size[2]; -		float max_luminance; -		float min_luminance; -		float exposure_adjust; -		float pad[3]; -	}; - -	struct LuminanceReduce { -		LuminanceReducePushConstant push_constant; -		LuminanceReduceShaderRD shader; -		RID shader_version; -		RID pipelines[LUMINANCE_REDUCE_MAX]; -	} luminance_reduce; - -	enum LuminanceReduceRasterMode { -		LUMINANCE_REDUCE_FRAGMENT_FIRST, -		LUMINANCE_REDUCE_FRAGMENT, -		LUMINANCE_REDUCE_FRAGMENT_FINAL, -		LUMINANCE_REDUCE_FRAGMENT_MAX -	}; - -	struct LuminanceReduceRasterPushConstant { -		int32_t source_size[2]; -		int32_t dest_size[2]; -		float exposure_adjust; -		float min_luminance; -		float max_luminance; -		uint32_t pad1; -	}; - -	struct LuminanceReduceFragment { -		LuminanceReduceRasterPushConstant push_constant; -		LuminanceReduceRasterShaderRD shader; -		RID shader_version; -		PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX]; -	} luminance_reduce_raster; -  	struct RoughnessLimiterPushConstant {  		int32_t screen_size[2];  		float curve; @@ -164,15 +117,11 @@ private:  	RBMap<TextureSamplerPair, RID> texture_sampler_to_compute_uniform_set_cache;  	RID _get_uniform_set_from_image(RID p_texture); -	RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);  	RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);  public:  	bool get_prefer_raster_effects(); -	void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); -	void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); -  	void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);  	void sort_buffer(RID p_uniform_set, int p_size); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index d426c4fc2e..1d45db8eaf 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -249,57 +249,6 @@ Ref<RenderSceneBuffers> RendererSceneRenderRD::render_buffers_create() {  	return rb;  } -void RendererSceneRenderRD::_allocate_luminance_textures(Ref<RenderSceneBuffersRD> rb) { -	ERR_FAIL_COND(!rb->luminance.current.is_null()); - -	Size2i internal_size = rb->get_internal_size(); -	int w = internal_size.x; -	int h = internal_size.y; - -	while (true) { -		w = MAX(w / 8, 1); -		h = MAX(h / 8, 1); - -		RD::TextureFormat tf; -		tf.format = RD::DATA_FORMAT_R32_SFLOAT; -		tf.width = w; -		tf.height = h; - -		bool final = w == 1 && h == 1; - -		if (_render_buffers_can_be_storage()) { -			tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; -			if (final) { -				tf.usage_bits |= RD::TEXTURE_USAGE_SAMPLING_BIT; -			} -		} else { -			tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; -		} - -		RID texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - -		rb->luminance.reduce.push_back(texture); -		if (!_render_buffers_can_be_storage()) { -			Vector<RID> fb; -			fb.push_back(texture); - -			rb->luminance.fb.push_back(RD::get_singleton()->framebuffer_create(fb)); -		} - -		if (final) { -			rb->luminance.current = RD::get_singleton()->texture_create(tf, RD::TextureView()); - -			if (!_render_buffers_can_be_storage()) { -				Vector<RID> fb; -				fb.push_back(rb->luminance.current); - -				rb->luminance.current_fb = RD::get_singleton()->framebuffer_create(fb); -			} -			break; -		} -	} -} -  void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) {  	Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;  	ERR_FAIL_COND(rb.is_null()); @@ -443,9 +392,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende  		RENDER_TIMESTAMP("Auto exposure");  		RD::get_singleton()->draw_command_begin_label("Auto exposure"); -		if (rb->luminance.current.is_null()) { -			_allocate_luminance_textures(rb); -		} + +		Ref<RendererRD::Luminance::LuminanceBuffers> luminance_buffers = luminance->get_luminance_buffers(rb); +  		uint64_t auto_exposure_version = RSG::camera_attributes->camera_attributes_get_auto_exposure_version(p_render_data->camera_attributes);  		bool set_immediate = auto_exposure_version != rb->get_auto_exposure_version();  		rb->set_auto_exposure_version(auto_exposure_version); @@ -453,16 +402,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende  		double step = RSG::camera_attributes->camera_attributes_get_auto_exposure_adjust_speed(p_render_data->camera_attributes) * time_step;  		float auto_exposure_min_sensitivity = RSG::camera_attributes->camera_attributes_get_auto_exposure_min_sensitivity(p_render_data->camera_attributes);  		float auto_exposure_max_sensitivity = RSG::camera_attributes->camera_attributes_get_auto_exposure_max_sensitivity(p_render_data->camera_attributes); -		if (can_use_storage) { -			RendererCompositorRD::singleton->get_effects()->luminance_reduction(internal_texture, internal_size, rb->luminance.reduce, rb->luminance.current, auto_exposure_min_sensitivity, auto_exposure_max_sensitivity, step, set_immediate); -		} else { -			RendererCompositorRD::singleton->get_effects()->luminance_reduction_raster(internal_texture, internal_size, rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, auto_exposure_min_sensitivity, auto_exposure_max_sensitivity, step, set_immediate); -		} +		luminance->luminance_reduction(internal_texture, internal_size, luminance_buffers, auto_exposure_min_sensitivity, auto_exposure_max_sensitivity, step, set_immediate); +  		// Swap final reduce with prev luminance. -		SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]); -		if (!can_use_storage) { -			SWAP(rb->luminance.current_fb, rb->luminance.fb.write[rb->luminance.fb.size() - 1]); -		}  		auto_exposure_scale = RSG::camera_attributes->camera_attributes_get_auto_exposure_scale(p_render_data->camera_attributes); @@ -496,8 +438,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende  				if (i == 0) {  					RID luminance_texture; -					if (RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) && rb->luminance.current.is_valid()) { -						luminance_texture = rb->luminance.current; +					if (RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes)) { +						luminance_texture = luminance->get_current_luminance_buffer(rb); // this will return and empty RID if we don't have an auto exposure buffer  					}  					RID source = rb->get_internal_texture(l);  					RID dest = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BLUR_1, l, i); @@ -530,9 +472,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende  		RendererRD::ToneMapper::TonemapSettings tonemap; -		if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) && rb->luminance.current.is_valid()) { +		tonemap.exposure_texture = luminance->get_current_luminance_buffer(rb); +		if (can_use_effects && RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) && tonemap.exposure_texture.is_valid()) {  			tonemap.use_auto_exposure = true; -			tonemap.exposure_texture = rb->luminance.current;  			tonemap.auto_exposure_scale = auto_exposure_scale;  		} else {  			tonemap.exposure_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE); @@ -746,10 +688,11 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>  	}  	if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) { -		if (p_render_buffers->luminance.current.is_valid()) { +		RID luminance_texture = luminance->get_current_luminance_buffer(p_render_buffers); +		if (luminance_texture.is_valid()) {  			Size2i rtsize = texture_storage->render_target_get_size(render_target); -			copy_effects->copy_to_fb_rect(p_render_buffers->luminance.current, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize / 8), false, true); +			copy_effects->copy_to_fb_rect(luminance_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize / 8), false, true);  		}  	} @@ -1334,6 +1277,7 @@ void RendererSceneRenderRD::init() {  	bool can_use_vrs = is_vrs_supported();  	bokeh_dof = memnew(RendererRD::BokehDOF(!can_use_storage));  	copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage)); +	luminance = memnew(RendererRD::Luminance(!can_use_storage));  	tone_mapper = memnew(RendererRD::ToneMapper);  	if (can_use_vrs) {  		vrs = memnew(RendererRD::VRS); @@ -1354,6 +1298,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {  	if (copy_effects) {  		memdelete(copy_effects);  	} +	if (luminance) { +		memdelete(luminance); +	}  	if (tone_mapper) {  		memdelete(tone_mapper);  	} diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 54f068c314..6fa2f7a570 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -38,6 +38,7 @@  #include "servers/rendering/renderer_rd/effects/bokeh_dof.h"  #include "servers/rendering/renderer_rd/effects/copy_effects.h"  #include "servers/rendering/renderer_rd/effects/fsr.h" +#include "servers/rendering/renderer_rd/effects/luminance.h"  #include "servers/rendering/renderer_rd/effects/tone_mapper.h"  #include "servers/rendering/renderer_rd/effects/vrs.h"  #include "servers/rendering/renderer_rd/environment/fog.h" @@ -105,6 +106,7 @@ protected:  	RendererRD::ForwardIDStorage *forward_id_storage = nullptr;  	RendererRD::BokehDOF *bokeh_dof = nullptr;  	RendererRD::CopyEffects *copy_effects = nullptr; +	RendererRD::Luminance *luminance = nullptr;  	RendererRD::ToneMapper *tone_mapper = nullptr;  	RendererRD::FSR *fsr = nullptr;  	RendererRD::VRS *vrs = nullptr; @@ -180,9 +182,6 @@ private:  	/* RENDER BUFFERS */ -	// TODO move into effects/luminance.h/cpp -	void _allocate_luminance_textures(Ref<RenderSceneBuffersRD> rb); -  	/* GI */  	bool screen_space_roughness_limiter = false;  	float screen_space_roughness_limiter_amount = 0.25; diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce.glsl index 0ee4cf6e31..0ee4cf6e31 100644 --- a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce.glsl diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl index 29ebd74a90..29ebd74a90 100644 --- a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster.glsl diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl index b8860f6518..b8860f6518 100644 --- a/servers/rendering/renderer_rd/shaders/luminance_reduce_raster_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index a953bac433..d67a848a40 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -94,28 +94,6 @@ void RenderSceneBuffersRD::cleanup() {  		free_named_texture(E.value);  	}  	named_textures.clear(); - -	// old stuff, to be re-evaluated... - -	for (int i = 0; i < luminance.fb.size(); i++) { -		RD::get_singleton()->free(luminance.fb[i]); -	} -	luminance.fb.clear(); - -	for (int i = 0; i < luminance.reduce.size(); i++) { -		RD::get_singleton()->free(luminance.reduce[i]); -	} -	luminance.reduce.clear(); - -	if (luminance.current_fb.is_valid()) { -		RD::get_singleton()->free(luminance.current_fb); -		luminance.current_fb = RID(); -	} - -	if (luminance.current.is_valid()) { -		RD::get_singleton()->free(luminance.current); -		luminance.current = RID(); -	}  }  void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h index 1bd542500c..ff946f410f 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h @@ -213,15 +213,6 @@ public:  	// 2 full size, 2 half size  	WeightBuffers weight_buffers[4]; // Only used in raster - -	struct Luminance { -		Vector<RID> reduce; -		RID current; - -		// used only on mobile renderer -		Vector<RID> fb; -		RID current_fb; -	} luminance;  };  #endif // RENDER_SCENE_BUFFERS_RD_H  |