diff options
-rw-r--r-- | doc/classes/ConfigFile.xml | 14 | ||||
-rw-r--r-- | doc/classes/VisualShaderNodeCustom.xml | 46 | ||||
-rw-r--r-- | editor/filesystem_dock.cpp | 73 | ||||
-rw-r--r-- | editor/filesystem_dock.h | 6 | ||||
-rw-r--r-- | editor/plugins/visual_shader_editor_plugin.cpp | 61 | ||||
-rw-r--r-- | editor/plugins/visual_shader_editor_plugin.h | 2 | ||||
-rw-r--r-- | editor/project_converter_3_to_4.cpp | 30 | ||||
-rw-r--r-- | editor/project_converter_3_to_4.h | 1 | ||||
-rw-r--r-- | modules/lightmapper_rd/config.py | 2 | ||||
-rw-r--r-- | modules/lightmapper_rd/register_types.cpp | 1 | ||||
-rw-r--r-- | scene/gui/spin_box.cpp | 3 | ||||
-rw-r--r-- | scene/resources/tile_set.cpp | 34 | ||||
-rw-r--r-- | scene/resources/visual_shader.cpp | 97 | ||||
-rw-r--r-- | scene/resources/visual_shader.h | 26 | ||||
-rw-r--r-- | servers/rendering_server.cpp | 1 |
15 files changed, 341 insertions, 56 deletions
diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml index 04e4164415..e6b28ae98e 100644 --- a/doc/classes/ConfigFile.xml +++ b/doc/classes/ConfigFile.xml @@ -163,7 +163,7 @@ <param index="0" name="path" type="String" /> <description> Loads the config file specified as a parameter. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on. - Returns one of the [enum Error] code constants ([constant OK] on success). + Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. </description> </method> <method name="load_encrypted"> @@ -172,7 +172,7 @@ <param index="1" name="key" type="PackedByteArray" /> <description> Loads the encrypted config file specified as a parameter, using the provided [param key] to decrypt it. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on. - Returns one of the [enum Error] code constants ([constant OK] on success). + Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. </description> </method> <method name="load_encrypted_pass"> @@ -181,7 +181,7 @@ <param index="1" name="password" type="String" /> <description> Loads the encrypted config file specified as a parameter, using the provided [param password] to decrypt it. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on. - Returns one of the [enum Error] code constants ([constant OK] on success). + Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. </description> </method> <method name="parse"> @@ -189,7 +189,7 @@ <param index="0" name="data" type="String" /> <description> Parses the passed string as the contents of a config file. The string is parsed and loaded in the ConfigFile object which the method was called on. - Returns one of the [enum Error] code constants ([constant OK] on success). + Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. </description> </method> <method name="save"> @@ -197,7 +197,7 @@ <param index="0" name="path" type="String" /> <description> Saves the contents of the [ConfigFile] object to the file specified as a parameter. The output file uses an INI-style structure. - Returns one of the [enum Error] code constants ([constant OK] on success). + Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. </description> </method> <method name="save_encrypted"> @@ -206,7 +206,7 @@ <param index="1" name="key" type="PackedByteArray" /> <description> Saves the contents of the [ConfigFile] object to the AES-256 encrypted file specified as a parameter, using the provided [param key] to encrypt it. The output file uses an INI-style structure. - Returns one of the [enum Error] code constants ([constant OK] on success). + Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. </description> </method> <method name="save_encrypted_pass"> @@ -215,7 +215,7 @@ <param index="1" name="password" type="String" /> <description> Saves the contents of the [ConfigFile] object to the AES-256 encrypted file specified as a parameter, using the provided [param password] to encrypt it. The output file uses an INI-style structure. - Returns one of the [enum Error] code constants ([constant OK] on success). + Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. </description> </method> <method name="set_value"> diff --git a/doc/classes/VisualShaderNodeCustom.xml b/doc/classes/VisualShaderNodeCustom.xml index 8a90d5dd0f..5db0dfb327 100644 --- a/doc/classes/VisualShaderNodeCustom.xml +++ b/doc/classes/VisualShaderNodeCustom.xml @@ -80,6 +80,14 @@ Defining this method is [b]required[/b]. If not overridden, the node has no input ports. </description> </method> + <method name="_get_input_port_default_value" qualifiers="virtual const"> + <return type="Variant" /> + <param index="0" name="port" type="int" /> + <description> + Override this method to define the default value for the specified input port. Prefer use this over [method VisualShaderNode.set_input_port_default_value]. + Defining this method is [b]required[/b]. If not overridden, the node has no default values for their input ports. + </description> + </method> <method name="_get_input_port_name" qualifiers="virtual const"> <return type="String" /> <param index="0" name="port" type="int" /> @@ -126,6 +134,37 @@ Defining this method is [b]optional[/b], but recommended. If not overridden, output ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] type. </description> </method> + <method name="_get_property_count" qualifiers="virtual const"> + <return type="int" /> + <description> + Override this method to define the number of the properties. + Defining this method is [b]optional[/b]. + </description> + </method> + <method name="_get_property_default_index" qualifiers="virtual const"> + <return type="int" /> + <param index="0" name="index" type="int" /> + <description> + Override this method to define the default index of the property of the associated custom node. + Defining this method is [b]optional[/b]. + </description> + </method> + <method name="_get_property_name" qualifiers="virtual const"> + <return type="String" /> + <param index="0" name="index" type="int" /> + <description> + Override this method to define the names of the property of the associated custom node. + Defining this method is [b]optional[/b]. + </description> + </method> + <method name="_get_property_options" qualifiers="virtual const"> + <return type="PackedStringArray" /> + <param index="0" name="index" type="int" /> + <description> + Override this method to define the options inside the drop-down list property of the associated custom node. + Defining this method is [b]optional[/b]. + </description> + </method> <method name="_get_return_icon_type" qualifiers="virtual const"> <return type="int" enum="VisualShaderNode.PortType" /> <description> @@ -149,5 +188,12 @@ Defining this method is [b]optional[/b]. If not overridden, it's [code]false[/code]. </description> </method> + <method name="get_option_index" qualifiers="const"> + <return type="int" /> + <param index="0" name="option" type="int" /> + <description> + Returns the selected index of the drop-down list option within a graph. You may use this function to define the specific behavior in the [method _get_code] or [method _get_global_code]. + </description> + </method> </methods> </class> diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 41591c366f..b80d3c1869 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1363,15 +1363,15 @@ void FileSystemDock::_get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Ve } } -void FileSystemDock::_find_remaps(EditorFileSystemDirectory *p_efsd, const Vector<String> &r_renames, Vector<String> &r_to_remaps) const { +void FileSystemDock::_find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> &p_renames, Vector<String> &r_file_owners) const { for (int i = 0; i < p_efsd->get_subdir_count(); i++) { - _find_remaps(p_efsd->get_subdir(i), r_renames, r_to_remaps); + _find_file_owners(p_efsd->get_subdir(i), p_renames, r_file_owners); } for (int i = 0; i < p_efsd->get_file_count(); i++) { Vector<String> deps = p_efsd->get_file_deps(i); for (int j = 0; j < deps.size(); j++) { - if (r_renames.has(deps[j])) { - r_to_remaps.push_back(p_efsd->get_file_path(i)); + if (p_renames.has(deps[j])) { + r_file_owners.push_back(p_efsd->get_file_path(i)); break; } } @@ -1562,22 +1562,22 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str } } -void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_remaps) const { +void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_file_owners) const { // The following code assumes that the following holds: // 1) EditorFileSystem contains the old paths/folder structure from before the rename/move. // 2) ResourceLoader can use the new paths without needing to call rescan. List<String> scenes_to_reload; - for (int i = 0; i < p_remaps.size(); ++i) { + for (int i = 0; i < p_file_owners.size(); ++i) { // Because we haven't called a rescan yet the found remap might still be an old path itself. - String file = p_renames.has(p_remaps[i]) ? p_renames[p_remaps[i]] : p_remaps[i]; + const String file = p_renames.has(p_file_owners[i]) ? p_renames[p_file_owners[i]] : p_file_owners[i]; print_verbose("Remapping dependencies for: " + file); - Error err = ResourceLoader::rename_dependencies(file, p_renames); + const Error err = ResourceLoader::rename_dependencies(file, p_renames); if (err == OK) { if (ResourceLoader::get_resource_type(file) == "PackedScene") { scenes_to_reload.push_back(file); } } else { - EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies:") + "\n" + p_remaps[i] + "\n"); + EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies for:") + "\n" + p_file_owners[i] + "\n"); } } @@ -1773,10 +1773,9 @@ void FileSystemDock::_rename_operation_confirm() { return; } - Vector<String> old_paths; HashMap<String, ResourceUID::ID> uids; - Vector<String> remaps; - _before_move(old_paths, uids, remaps); + Vector<String> file_owners; // The files that use these moved/renamed resource files. + _before_move(uids, file_owners); HashMap<String, String> file_renames; HashMap<String, String> folder_renames; @@ -1784,7 +1783,7 @@ void FileSystemDock::_rename_operation_confirm() { int current_tab = EditorSceneTabs::get_singleton()->get_current_tab(); _update_resource_paths_after_move(file_renames, uids); - _update_dependencies_after_move(file_renames, remaps); + _update_dependencies_after_move(file_renames, file_owners); _update_project_settings_after_move(file_renames, folder_renames); _update_favorites_list_after_move(file_renames, folder_renames); @@ -1910,10 +1909,9 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop } } - Vector<String> old_paths; HashMap<String, ResourceUID::ID> uids; - Vector<String> remaps; - _before_move(old_paths, uids, remaps); + Vector<String> file_owners; // The files that use these moved/renamed resource files. + _before_move(uids, file_owners); bool is_moved = false; HashMap<String, String> file_renames; @@ -1936,7 +1934,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop if (is_moved) { int current_tab = EditorSceneTabs::get_singleton()->get_current_tab(); _update_resource_paths_after_move(file_renames, uids); - _update_dependencies_after_move(file_renames, remaps); + _update_dependencies_after_move(file_renames, file_owners); _update_project_settings_after_move(file_renames, folder_renames); _update_favorites_list_after_move(file_renames, folder_renames); @@ -1951,20 +1949,43 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop } } -void FileSystemDock::_before_move(Vector<String> &r_old_paths, HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_remaps) const { +void FileSystemDock::_before_move(HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_file_owners) const { + Vector<String> renamed_files; for (int i = 0; i < to_move.size(); i++) { - r_old_paths.push_back(to_move[i].path); - ResourceUID::ID uid = ResourceLoader::get_resource_uid(to_move[i].path); - if (uid != ResourceUID::INVALID_ID) { - r_uids[to_move[i].path] = uid; + if (to_move[i].is_file) { + renamed_files.push_back(to_move[i].path); + ResourceUID::ID uid = ResourceLoader::get_resource_uid(to_move[i].path); + if (uid != ResourceUID::INVALID_ID) { + r_uids[to_move[i].path] = uid; + } + } else { + EditorFileSystemDirectory *current_folder = EditorFileSystem::get_singleton()->get_filesystem_path(to_move[i].path); + List<EditorFileSystemDirectory *> folders; + folders.push_back(current_folder); + while (folders.front()) { + current_folder = folders.front()->get(); + for (int j = 0; j < current_folder->get_file_count(); j++) { + const String file_path = current_folder->get_file_path(j); + renamed_files.push_back(file_path); + ResourceUID::ID uid = ResourceLoader::get_resource_uid(file_path); + if (uid != ResourceUID::INVALID_ID) { + r_uids[file_path] = uid; + } + } + for (int j = 0; j < current_folder->get_subdir_count(); j++) { + folders.push_back(current_folder->get_subdir(j)); + } + folders.pop_front(); + } } } - _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), r_old_paths, r_remaps); + // Look for files that use these moved/renamed resource files. + _find_file_owners(EditorFileSystem::get_singleton()->get_filesystem(), renamed_files, r_file_owners); // Open scenes with dependencies on the ones about to be moved will be reloaded, // so save them first to prevent losing unsaved changes. - EditorNode::get_singleton()->save_scene_list(r_remaps); + EditorNode::get_singleton()->save_scene_list(r_file_owners); } Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion) const { @@ -2201,6 +2222,10 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected break; } + // Rename has same logic as move for resource files. + to_move.clear(); + to_move.push_back(to_rename); + if (tree->has_focus()) { // Edit node in Tree. tree->edit_selected(true); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index e900ac0037..818b91bdb9 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -262,11 +262,11 @@ private: void _update_import_dock(); void _get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const; - void _find_remaps(EditorFileSystemDirectory *p_efsd, const Vector<String> &r_renames, Vector<String> &r_to_remaps) const; + void _find_file_owners(EditorFileSystemDirectory *p_efsd, const Vector<String> &p_renames, Vector<String> &r_file_owners) const; void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, HashMap<String, String> &p_file_renames, HashMap<String, String> &p_folder_renames); void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; - void _before_move(Vector<String> &r_old_paths, HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_remaps) const; - void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_remaps) const; + void _before_move(HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_file_owners) const; + void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_file_owners) const; void _update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const; void _update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const; void _update_project_settings_after_move(const HashMap<String, String> &p_renames, const HashMap<String, String> &p_folders_renames); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 25cbbbf6de..8b1053b79b 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -551,6 +551,47 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool } } + if (custom_node.is_valid()) { + bool first = true; + VBoxContainer *vbox = nullptr; + + for (int i = 0; i < custom_node->dp_props.size(); i++) { + const VisualShaderNodeCustom::DropDownListProperty &dp = custom_node->dp_props[i]; + + if (first) { + first = false; + vbox = memnew(VBoxContainer); + node->add_child(vbox); + port_offset++; + } + + HBoxContainer *hbox = memnew(HBoxContainer); + vbox->add_child(hbox); + hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL); + + String prop_name = dp.name.strip_edges(); + if (!prop_name.is_empty()) { + Label *label = memnew(Label); + label->set_text(prop_name + ":"); + hbox->add_child(label); + } + + OptionButton *op = memnew(OptionButton); + hbox->add_child(op); + op->set_h_size_flags(Control::SIZE_EXPAND_FILL); + op->connect("item_selected", callable_mp(editor, &VisualShaderEditor::_set_custom_node_option).bind(p_id, i), CONNECT_DEFERRED); + + for (const String &s : dp.options) { + op->add_item(s); + } + if (custom_node->dp_selected_cache.has(i)) { + op->select(custom_node->dp_selected_cache[i]); + } else { + op->select(0); + } + } + } + Ref<VisualShaderNodeCurveTexture> curve = vsnode; Ref<VisualShaderNodeCurveXYZTexture> curve_xyz = vsnode; @@ -2704,6 +2745,22 @@ void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node, editing_port = p_port; } +void VisualShaderEditor::_set_custom_node_option(int p_index, int p_node, int p_op) { + VisualShader::Type type = get_current_shader_type(); + Ref<VisualShaderNodeCustom> node = visual_shader->get_node(type, p_node); + if (node.is_null()) { + return; + } + + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Set Custom Node Option")); + undo_redo->add_do_method(node.ptr(), "_set_option_index", p_op, p_index); + undo_redo->add_undo_method(node.ptr(), "_set_option_index", p_op, node->get_option_index(p_op)); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->commit_action(); +} + void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, const Vector<Variant> &p_ops) { // INPUT { @@ -3084,7 +3141,9 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri } VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsn); ERR_FAIL_NULL(custom_node); - custom_node->update_ports(); + custom_node->update_property_default_values(); + custom_node->update_input_port_default_values(); + custom_node->update_properties(); } bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index e0a0f3a096..8629e64467 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -493,6 +493,8 @@ class VisualShaderEditor : public VBoxContainer { void _varying_unselected(); void _update_varying_tree(); + void _set_custom_node_option(int p_index, int p_node, int p_op); + Vector2 menu_point; void _node_menu_id_pressed(int p_idx); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index b2994f3065..d6ed5eb995 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -139,6 +139,9 @@ public: LocalVector<RegEx *> color_regexes; LocalVector<String> color_renamed; + RegEx color_hexadecimal_short_constructor = RegEx("Color\\(\"#?([a-fA-F0-9]{1})([a-fA-F0-9]{3})\\b"); + RegEx color_hexadecimal_full_constructor = RegEx("Color\\(\"#?([a-fA-F0-9]{2})([a-fA-F0-9]{6})\\b"); + // Classes. LocalVector<RegEx *> class_tscn_regexes; LocalVector<RegEx *> class_gd_regexes; @@ -409,6 +412,8 @@ bool ProjectConverter3To4::convert() { rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, source_lines); custom_rename(source_lines, "\\.shader", ".gdshader"); + + convert_hexadecimal_colors(source_lines, reg_container); } else if (file_name.ends_with(".tscn")) { fix_pause_mode(source_lines, reg_container); @@ -429,6 +434,8 @@ bool ProjectConverter3To4::convert() { rename_common(RenamesMap3To4::theme_override_renames, reg_container.theme_override_regexes, source_lines); custom_rename(source_lines, "\\.shader", ".gdshader"); + + convert_hexadecimal_colors(source_lines, reg_container); } else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods. rename_classes(source_lines, reg_container); // Using only specialized function. rename_common(RenamesMap3To4::csharp_function_renames, reg_container.csharp_function_regexes, source_lines); @@ -438,6 +445,7 @@ bool ProjectConverter3To4::convert() { rename_csharp_functions(source_lines, reg_container); rename_csharp_attributes(source_lines, reg_container); custom_rename(source_lines, "public class ", "public partial class "); + convert_hexadecimal_colors(source_lines, reg_container); } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) { rename_common(RenamesMap3To4::shaders_renames, reg_container.shaders_regexes, source_lines); } else if (file_name.ends_with("tres")) { @@ -1004,7 +1012,10 @@ bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { valid = valid && test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid && test_conversion_gdscript_builtin("button.pressed SF", "button.pressed SF", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid && test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "custom rename", reg_container); + valid = valid && test_conversion_with_regex("Color(\"#f47d\")", "Color(\"#47df\")", &ProjectConverter3To4::convert_hexadecimal_colors, "color literals", reg_container); + valid = valid && test_conversion_with_regex("Color(\"#ff478cbf\")", "Color(\"#478cbfff\")", &ProjectConverter3To4::convert_hexadecimal_colors, "color literals", reg_container); + valid = valid && test_conversion_with_regex("Color(\"#de32bf\")", "Color(\"#de32bf\")", &ProjectConverter3To4::convert_hexadecimal_colors, "color literals", reg_container); + valid = valid && test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "color constants", reg_container); // Note: Do not change to *scancode*, it is applied before that conversion. valid = valid && test_conversion_with_regex("\"device\":-1,\"scancode\":16777231,\"physical_scancode\":16777232", "\"device\":-1,\"scancode\":4194319,\"physical_scancode\":4194320", &ProjectConverter3To4::rename_input_map_scancode, "custom rename", reg_container); @@ -1458,6 +1469,23 @@ void ProjectConverter3To4::rename_colors(Vector<SourceLine> &source_lines, const } }; +// Convert hexadecimal colors from ARGB to RGBA +void ProjectConverter3To4::convert_hexadecimal_colors(Vector<SourceLine> &source_lines, const RegExContainer ®_container) { + for (SourceLine &source_line : source_lines) { + if (source_line.is_comment) { + continue; + } + + String &line = source_line.line; + if (uint64_t(line.length()) <= maximum_line_length) { + if (line.contains("Color(\"")) { + line = reg_container.color_hexadecimal_short_constructor.sub(line, "Color(\"#$2$1", true); + line = reg_container.color_hexadecimal_full_constructor.sub(line, "Color(\"#$2$1", true); + } + } + } +} + Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer ®_container) { Vector<String> found_renames; diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h index e26f4ee49a..2afd0a24e8 100644 --- a/editor/project_converter_3_to_4.h +++ b/editor/project_converter_3_to_4.h @@ -75,6 +75,7 @@ class ProjectConverter3To4 { void fix_pause_mode(Vector<SourceLine> &source_lines, const RegExContainer ®_container); void rename_colors(Vector<SourceLine> &source_lines, const RegExContainer ®_container); + void convert_hexadecimal_colors(Vector<SourceLine> &source_lines, const RegExContainer ®_container); Vector<String> check_for_rename_colors(Vector<String> &lines, const RegExContainer ®_container); void rename_classes(Vector<SourceLine> &source_lines, const RegExContainer ®_container); diff --git a/modules/lightmapper_rd/config.py b/modules/lightmapper_rd/config.py index d22f9454ed..ecc61c2d7e 100644 --- a/modules/lightmapper_rd/config.py +++ b/modules/lightmapper_rd/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return env.editor_build and platform not in ["android", "ios"] def configure(env): diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp index 7ec4a40766..984ce88316 100644 --- a/modules/lightmapper_rd/register_types.cpp +++ b/modules/lightmapper_rd/register_types.cpp @@ -58,7 +58,6 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) { GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_probe_ray_count", 512); GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048); GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64); - GLOBAL_DEF("rendering/lightmapping/primitive_meshes/texel_size", 0.2); #ifndef _3D_DISABLED GDREGISTER_CLASS(LightmapperRD); Lightmapper::create_gpu = create_lightmapper_rd; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index e13fd21949..26dbe1cb0c 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -263,6 +263,9 @@ void SpinBox::_notification(int p_what) { _update_text(); } break; + case NOTIFICATION_VISIBILITY_CHANGED: + drag.allowed = false; + [[fallthrough]]; case NOTIFICATION_EXIT_TREE: { _release_mouse(); } break; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index b372fcb1e9..dce0d87d10 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -327,22 +327,22 @@ TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terra const int TileSet::INVALID_SOURCE = -1; const char *TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[] = { - "right_side", - "right_corner", - "bottom_right_side", - "bottom_right_corner", - "bottom_side", - "bottom_corner", - "bottom_left_side", - "bottom_left_corner", - "left_side", - "left_corner", - "top_left_side", - "top_left_corner", - "top_side", - "top_corner", - "top_right_side", - "top_right_corner" + PNAME("right_side"), + PNAME("right_corner"), + PNAME("bottom_right_side"), + PNAME("bottom_right_corner"), + PNAME("bottom_side"), + PNAME("bottom_corner"), + PNAME("bottom_left_side"), + PNAME("bottom_left_corner"), + PNAME("left_side"), + PNAME("left_corner"), + PNAME("top_left_side"), + PNAME("top_left_corner"), + PNAME("top_side"), + PNAME("top_corner"), + PNAME("top_right_side"), + PNAME("top_right_corner"), }; // -- Shape and layout -- @@ -5839,7 +5839,7 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); if (is_valid_terrain_peering_bit(bit)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i])); + property_info = PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("terrains_peering_bit"), TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i])); if (get_terrain_peering_bit(bit) == -1) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index ea1207605c..489b866e70 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -435,8 +435,62 @@ VisualShaderNode::VisualShaderNode() { ///////////////////////////////////////////////////////// +void VisualShaderNodeCustom::update_property_default_values() { + int prop_count; + if (GDVIRTUAL_CALL(_get_property_count, prop_count)) { + for (int i = 0; i < prop_count; i++) { + int selected = 0; + if (GDVIRTUAL_CALL(_get_property_default_index, i, selected)) { + dp_selected_cache[i] = selected; + } + } + } +} + +void VisualShaderNodeCustom::update_input_port_default_values() { + int input_port_count; + if (GDVIRTUAL_CALL(_get_input_port_count, input_port_count)) { + for (int i = 0; i < input_port_count; i++) { + Variant value; + if (GDVIRTUAL_CALL(_get_input_port_default_value, i, value)) { + default_input_values[i] = value; + } + } + } +} + void VisualShaderNodeCustom::update_ports() { { + dp_props.clear(); + int prop_count; + if (GDVIRTUAL_CALL(_get_property_count, prop_count)) { + for (int i = 0; i < prop_count; i++) { + DropDownListProperty prop; + if (!GDVIRTUAL_CALL(_get_property_name, i, prop.name)) { + prop.name = "prop"; + } + if (!GDVIRTUAL_CALL(_get_property_options, i, prop.options)) { + prop.options.push_back("Default"); + } + dp_props.push_back(prop); + } + } + } + + { + Vector<String> vprops = properties.split(";", false); + for (int i = 0; i < vprops.size(); i++) { + Vector<String> arr = vprops[i].split(",", false); + ERR_FAIL_COND(arr.size() != 2); + ERR_FAIL_COND(!arr[0].is_valid_int()); + ERR_FAIL_COND(!arr[1].is_valid_int()); + int index = arr[0].to_int(); + int selected = arr[1].to_int(); + dp_selected_cache[index] = selected; + } + } + + { input_ports.clear(); int input_port_count; if (GDVIRTUAL_CALL(_get_input_port_count, input_port_count)) { @@ -479,6 +533,15 @@ void VisualShaderNodeCustom::update_ports() { } } +void VisualShaderNodeCustom::update_properties() { + properties = ""; + for (const KeyValue<int, int> &p : dp_selected_cache) { + if (p.value != 0) { + properties += itos(p.key) + "," + itos(p.value) + ";"; + } + } +} + String VisualShaderNodeCustom::get_caption() const { String ret = "Unnamed"; GDVIRTUAL_CALL(_get_name, ret); @@ -635,6 +698,14 @@ void VisualShaderNodeCustom::_set_initialized(bool p_enabled) { is_initialized = p_enabled; } +void VisualShaderNodeCustom::_set_properties(const String &p_properties) { + properties = p_properties; +} + +String VisualShaderNodeCustom::_get_properties() const { + return properties; +} + String VisualShaderNodeCustom::_get_name() const { String ret; GDVIRTUAL_CALL(_get_name, ret); @@ -665,6 +736,21 @@ bool VisualShaderNodeCustom::_is_highend() const { return ret; } +void VisualShaderNodeCustom::_set_option_index(int p_option, int p_value) { + dp_selected_cache[p_option] = p_value; + update_properties(); + update_ports(); + update_input_port_default_values(); + emit_changed(); +} + +int VisualShaderNodeCustom::get_option_index(int p_option) const { + if (!dp_selected_cache.has(p_option)) { + return 0; + } + return dp_selected_cache[p_option]; +} + void VisualShaderNodeCustom::_bind_methods() { GDVIRTUAL_BIND(_get_name); GDVIRTUAL_BIND(_get_description); @@ -673,10 +759,15 @@ void VisualShaderNodeCustom::_bind_methods() { GDVIRTUAL_BIND(_get_input_port_count); GDVIRTUAL_BIND(_get_input_port_type, "port"); GDVIRTUAL_BIND(_get_input_port_name, "port"); + GDVIRTUAL_BIND(_get_input_port_default_value, "port"); GDVIRTUAL_BIND(_get_default_input_port, "type"); GDVIRTUAL_BIND(_get_output_port_count); GDVIRTUAL_BIND(_get_output_port_type, "port"); GDVIRTUAL_BIND(_get_output_port_name, "port"); + GDVIRTUAL_BIND(_get_property_count); + GDVIRTUAL_BIND(_get_property_name, "index"); + GDVIRTUAL_BIND(_get_property_default_index, "index"); + GDVIRTUAL_BIND(_get_property_options, "index"); GDVIRTUAL_BIND(_get_code, "input_vars", "output_vars", "mode", "type"); GDVIRTUAL_BIND(_get_func_code, "mode", "type"); GDVIRTUAL_BIND(_get_global_code, "mode"); @@ -686,8 +777,14 @@ void VisualShaderNodeCustom::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized); ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized); ClassDB::bind_method(D_METHOD("_set_input_port_default_value", "port", "value"), &VisualShaderNodeCustom::_set_input_port_default_value); + ClassDB::bind_method(D_METHOD("_set_option_index", "option", "value"), &VisualShaderNodeCustom::_set_option_index); + ClassDB::bind_method(D_METHOD("_set_properties", "properties"), &VisualShaderNodeCustom::_set_properties); + ClassDB::bind_method(D_METHOD("_get_properties"), &VisualShaderNodeCustom::_get_properties); + + ClassDB::bind_method(D_METHOD("get_option_index", "option"), &VisualShaderNodeCustom::get_option_index); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "initialized", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_initialized", "_is_initialized"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "properties", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_properties", "_get_properties"); } VisualShaderNodeCustom::VisualShaderNodeCustom() { diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 1d23b80839..501a538c86 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -257,12 +257,12 @@ class VisualShaderNode : public Resource { int port_preview = -1; - HashMap<int, Variant> default_input_values; HashMap<int, bool> connected_input_ports; HashMap<int, int> connected_output_ports; HashMap<int, bool> expanded_output_ports; protected: + HashMap<int, Variant> default_input_values; bool simple_decl = true; bool disabled = false; bool closable = false; @@ -363,8 +363,19 @@ class VisualShaderNodeCustom : public VisualShaderNode { bool is_initialized = false; List<Port> input_ports; List<Port> output_ports; + struct Property { + String name; + }; + struct DropDownListProperty : public Property { + Vector<String> options; + }; + HashMap<int, int> dp_selected_cache; + HashMap<int, int> dp_default_cache; + List<DropDownListProperty> dp_props; + String properties; friend class VisualShaderEditor; + friend class VisualShaderGraphPlugin; protected: virtual String get_caption() const override; @@ -390,10 +401,15 @@ protected: GDVIRTUAL0RC(int, _get_input_port_count) GDVIRTUAL1RC(PortType, _get_input_port_type, int) GDVIRTUAL1RC(String, _get_input_port_name, int) + GDVIRTUAL1RC(Variant, _get_input_port_default_value, int) GDVIRTUAL1RC(int, _get_default_input_port, PortType) GDVIRTUAL0RC(int, _get_output_port_count) GDVIRTUAL1RC(PortType, _get_output_port_type, int) GDVIRTUAL1RC(String, _get_output_port_name, int) + GDVIRTUAL0RC(int, _get_property_count) + GDVIRTUAL1RC(String, _get_property_name, int) + GDVIRTUAL1RC(int, _get_property_default_index, int) + GDVIRTUAL1RC(Vector<String>, _get_property_options, int) GDVIRTUAL4RC(String, _get_code, TypedArray<String>, TypedArray<String>, Shader::Mode, VisualShader::Type) GDVIRTUAL2RC(String, _get_func_code, Shader::Mode, VisualShader::Type) GDVIRTUAL1RC(String, _get_global_code, Shader::Mode) @@ -414,16 +430,24 @@ protected: public: VisualShaderNodeCustom(); + void update_property_default_values(); + void update_input_port_default_values(); void update_ports(); + void update_properties(); bool _is_initialized(); void _set_initialized(bool p_enabled); + void _set_properties(const String &p_properties); + String _get_properties() const; String _get_name() const; String _get_description() const; String _get_category() const; PortType _get_return_icon_type() const; bool _is_highend() const; + void _set_option_index(int p_op, int p_index); + + int get_option_index(int p_op) const; }; ///// diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index b7c40600cb..9a3b7b9f3c 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2983,6 +2983,7 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/limits/global_shader_variables/buffer_size", 65536); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/probe_capture/update_speed", PROPERTY_HINT_RANGE, "0.001,256,0.001"), 15); + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/lightmapping/primitive_meshes/texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/probe_ray_count", PROPERTY_HINT_ENUM, "8 (Fastest),16,32,64,96,128 (Slowest)"), 1); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/global_illumination/sdfgi/frames_to_converge", PROPERTY_HINT_ENUM, "5 (Less Latency but Lower Quality),10,15,20,25,30 (More Latency but Higher Quality)"), 5); |