summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/classes/ConfigFile.xml14
-rw-r--r--doc/classes/VisualShaderNodeCustom.xml46
-rw-r--r--editor/filesystem_dock.cpp73
-rw-r--r--editor/filesystem_dock.h6
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp61
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h2
-rw-r--r--editor/project_converter_3_to_4.cpp30
-rw-r--r--editor/project_converter_3_to_4.h1
-rw-r--r--modules/lightmapper_rd/config.py2
-rw-r--r--modules/lightmapper_rd/register_types.cpp1
-rw-r--r--scene/gui/spin_box.cpp3
-rw-r--r--scene/resources/tile_set.cpp34
-rw-r--r--scene/resources/visual_shader.cpp97
-rw-r--r--scene/resources/visual_shader.h26
-rw-r--r--servers/rendering_server.cpp1
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 &reg_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 &reg_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 &reg_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 &reg_container);
void rename_colors(Vector<SourceLine> &source_lines, const RegExContainer &reg_container);
+ void convert_hexadecimal_colors(Vector<SourceLine> &source_lines, const RegExContainer &reg_container);
Vector<String> check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container);
void rename_classes(Vector<SourceLine> &source_lines, const RegExContainer &reg_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);