summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/action_map_editor.cpp14
-rw-r--r--editor/code_editor.cpp1
-rw-r--r--editor/debugger/editor_debugger_node.cpp5
-rw-r--r--editor/doc_tools.cpp111
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_export.cpp14
-rw-r--r--editor/editor_help.cpp334
-rw-r--r--editor/editor_help.h2
-rw-r--r--editor/editor_help_search.cpp24
-rw-r--r--editor/editor_help_search.h16
-rw-r--r--editor/editor_node.cpp122
-rw-r--r--editor/editor_node.h12
-rw-r--r--editor/editor_properties.cpp24
-rw-r--r--editor/editor_properties_array_dict.cpp21
-rw-r--r--editor/editor_resource_preview.cpp217
-rw-r--r--editor/editor_resource_preview.h9
-rw-r--r--editor/editor_run.cpp2
-rw-r--r--editor/editor_spin_slider.cpp14
-rw-r--r--editor/editor_spin_slider.h1
-rw-r--r--editor/editor_toaster.cpp7
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/find_in_files.cpp63
-rw-r--r--editor/icons/FogMaterial.svg1
-rw-r--r--editor/icons/FogVolume.svg1
-rw-r--r--editor/icons/GradientTexture2D.svg1
-rw-r--r--editor/icons/OverbrightIndicator.svg2
-rw-r--r--editor/import/collada.cpp28
-rw-r--r--editor/import/editor_import_collada.cpp3
-rw-r--r--editor/import/resource_importer_scene.cpp16
-rw-r--r--editor/import/resource_importer_wav.cpp14
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp14
-rw-r--r--editor/plugins/curve_editor_plugin.cpp6
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp3
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp410
-rw-r--r--editor/plugins/item_list_editor_plugin.h250
-rw-r--r--editor/plugins/material_editor_plugin.cpp84
-rw-r--r--editor/plugins/material_editor_plugin.h18
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp135
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h17
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp7
-rw-r--r--editor/plugins/node_3d_editor_plugin.h1
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp9
-rw-r--r--editor/plugins/script_editor_plugin.cpp5
-rw-r--r--editor/plugins/script_text_editor.cpp11
-rw-r--r--editor/plugins/shader_editor_plugin.cpp4
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp703
-rw-r--r--editor/plugins/tiles/tile_map_editor.h37
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp10
-rw-r--r--editor/plugins/tiles/tile_set_editor.h6
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp10
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.h5
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp266
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h35
-rw-r--r--editor/project_manager.cpp22
-rw-r--r--editor/property_editor.cpp10
-rw-r--r--editor/rename_dialog.cpp2
-rw-r--r--editor/shader_create_dialog.cpp5
57 files changed, 1775 insertions, 1393 deletions
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index fc7e7389d5..519dd654ef 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -238,10 +238,16 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> &
Ref<InputEventJoypadButton> joyb = p_event;
Ref<InputEventJoypadMotion> joym = p_event;
- int type = k.is_valid() ? INPUT_KEY : joyb.is_valid() ? INPUT_JOY_BUTTON :
- joym.is_valid() ? INPUT_JOY_MOTION :
- mb.is_valid() ? INPUT_MOUSE_BUTTON :
- 0;
+ int type = 0;
+ if (k.is_valid()) {
+ type = INPUT_KEY;
+ } else if (joyb.is_valid()) {
+ type = INPUT_JOY_BUTTON;
+ } else if (joym.is_valid()) {
+ type = INPUT_JOY_MOTION;
+ } else if (mb.is_valid()) {
+ type = INPUT_MOUSE_BUTTON;
+ }
if (!(allowed_input_types & type)) {
return;
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 7bf82fbd1b..1902ae66fb 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1824,6 +1824,7 @@ CodeTextEditor::CodeTextEditor() {
text_editor->set_draw_line_numbers(true);
text_editor->set_highlight_matching_braces_enabled(true);
text_editor->set_auto_indent_enabled(true);
+ text_editor->set_deselect_on_focus_loss_enabled(false);
status_bar = memnew(HBoxContainer);
add_child(status_bar);
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 188f5708aa..391839d639 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -265,15 +265,20 @@ void EditorDebuggerNode::_notification(int p_what) {
if (error_count == 0 && warning_count == 0) {
debugger_button->set_text(TTR("Debugger"));
+ debugger_button->remove_theme_color_override("font_color");
debugger_button->set_icon(Ref<Texture2D>());
} else {
debugger_button->set_text(TTR("Debugger") + " (" + itos(error_count + warning_count) + ")");
if (error_count >= 1 && warning_count >= 1) {
debugger_button->set_icon(get_theme_icon(SNAME("ErrorWarning"), SNAME("EditorIcons")));
+ // Use error color to represent the highest level of severity reported.
+ debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
} else if (error_count >= 1) {
debugger_button->set_icon(get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
+ debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
} else {
debugger_button->set_icon(get_theme_icon(SNAME("Warning"), SNAME("EditorIcons")));
+ debugger_button->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
}
}
last_error_count = error_count;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index beead74c53..61cc6dbd4a 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -57,25 +57,21 @@ void DocTools::merge_from(const DocTools &p_data) {
c.brief_description = cf.brief_description;
c.tutorials = cf.tutorials;
- for (int i = 0; i < c.methods.size(); i++) {
- DocData::MethodDoc &m = c.methods.write[i];
+ for (int i = 0; i < c.constructors.size(); i++) {
+ DocData::MethodDoc &m = c.constructors.write[i];
- for (int j = 0; j < cf.methods.size(); j++) {
- if (cf.methods[j].name != m.name) {
+ for (int j = 0; j < cf.constructors.size(); j++) {
+ if (cf.constructors[j].name != m.name) {
continue;
}
- const char *operator_prefix = "operator "; // Operators use a space at the end, making this prefix an invalid identifier (and differentiating from methods).
-
- if (cf.methods[j].name == c.name || cf.methods[j].name.begins_with(operator_prefix)) {
- // Since constructors and operators can repeat, we need to check the type of
+ {
+ // Since constructors can repeat, we need to check the type of
// the arguments so we make sure they are different.
-
- if (cf.methods[j].arguments.size() != m.arguments.size()) {
+ if (cf.constructors[j].arguments.size() != m.arguments.size()) {
continue;
}
-
- int arg_count = cf.methods[j].arguments.size();
+ int arg_count = cf.constructors[j].arguments.size();
Vector<bool> arg_used;
arg_used.resize(arg_count);
for (int l = 0; l < arg_count; ++l) {
@@ -85,7 +81,7 @@ void DocTools::merge_from(const DocTools &p_data) {
// have to check one by one so we make sure we have an exact match
for (int k = 0; k < arg_count; ++k) {
for (int l = 0; l < arg_count; ++l) {
- if (cf.methods[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) {
+ if (cf.constructors[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) {
arg_used.write[l] = true;
break;
}
@@ -102,6 +98,21 @@ void DocTools::merge_from(const DocTools &p_data) {
}
}
+ const DocData::MethodDoc &mf = cf.constructors[j];
+
+ m.description = mf.description;
+ break;
+ }
+ }
+
+ for (int i = 0; i < c.methods.size(); i++) {
+ DocData::MethodDoc &m = c.methods.write[i];
+
+ for (int j = 0; j < cf.methods.size(); j++) {
+ if (cf.methods[j].name != m.name) {
+ continue;
+ }
+
const DocData::MethodDoc &mf = cf.methods[j];
m.description = mf.description;
@@ -165,6 +176,54 @@ void DocTools::merge_from(const DocTools &p_data) {
}
}
+ for (int i = 0; i < c.operators.size(); i++) {
+ DocData::MethodDoc &m = c.operators.write[i];
+
+ for (int j = 0; j < cf.operators.size(); j++) {
+ if (cf.operators[j].name != m.name) {
+ continue;
+ }
+
+ {
+ // Since operators can repeat, we need to check the type of
+ // the arguments so we make sure they are different.
+ if (cf.operators[j].arguments.size() != m.arguments.size()) {
+ continue;
+ }
+ int arg_count = cf.operators[j].arguments.size();
+ Vector<bool> arg_used;
+ arg_used.resize(arg_count);
+ for (int l = 0; l < arg_count; ++l) {
+ arg_used.write[l] = false;
+ }
+ // also there is no guarantee that argument ordering will match, so we
+ // have to check one by one so we make sure we have an exact match
+ for (int k = 0; k < arg_count; ++k) {
+ for (int l = 0; l < arg_count; ++l) {
+ if (cf.operators[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) {
+ arg_used.write[l] = true;
+ break;
+ }
+ }
+ }
+ bool not_the_same = false;
+ for (int l = 0; l < arg_count; ++l) {
+ if (!arg_used[l]) { // at least one of the arguments was different
+ not_the_same = true;
+ }
+ }
+ if (not_the_same) {
+ continue;
+ }
+ }
+
+ const DocData::MethodDoc &mf = cf.operators[j];
+
+ m.description = mf.description;
+ break;
+ }
+ }
+
#ifndef MODULE_MONO_ENABLED
// The Mono module defines some properties that we want to keep when
// re-generating docs with a non-Mono build, to prevent pointless diffs
@@ -650,11 +709,6 @@ void DocTools::generate(bool p_basic_types) {
DocData::MethodDoc method;
method.name = mi.name;
- if (method.name == cname) {
- method.qualifiers = "constructor";
- } else if (method.name.begins_with("operator")) {
- method.qualifiers = "operator";
- }
for (int j = 0; j < mi.arguments.size(); j++) {
PropertyInfo arginfo = mi.arguments[j];
@@ -694,7 +748,13 @@ void DocTools::generate(bool p_basic_types) {
method.qualifiers += "static";
}
- c.methods.push_back(method);
+ if (method.name == cname) {
+ c.constructors.push_back(method);
+ } else if (method.name.begins_with("operator")) {
+ c.operators.push_back(method);
+ } else {
+ c.methods.push_back(method);
+ }
}
List<PropertyInfo> properties;
@@ -916,7 +976,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
methods.push_back(method);
} else {
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + ".");
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + ", expected " + element + ".");
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section) {
@@ -1044,10 +1104,15 @@ Error DocTools::_load(Ref<XMLParser> parser) {
break; // End of <tutorials>.
}
}
+ } else if (name2 == "constructors") {
+ Error err2 = _parse_methods(parser, c.constructors);
+ ERR_FAIL_COND_V(err2, err2);
} else if (name2 == "methods") {
Error err2 = _parse_methods(parser, c.methods);
ERR_FAIL_COND_V(err2, err2);
-
+ } else if (name2 == "operators") {
+ Error err2 = _parse_methods(parser, c.operators);
+ ERR_FAIL_COND_V(err2, err2);
} else if (name2 == "signals") {
Error err2 = _parse_methods(parser, c.signals);
ERR_FAIL_COND_V(err2, err2);
@@ -1269,6 +1334,8 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
}
_write_string(f, 1, "</tutorials>");
+ _write_method_doc(f, "constructor", c.constructors);
+
_write_method_doc(f, "method", c.methods);
if (!c.properties.is_empty()) {
@@ -1344,6 +1411,8 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
_write_string(f, 1, "</theme_items>");
}
+ _write_method_doc(f, "operator", c.operators);
+
_write_string(f, 0, "</class>");
}
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index c895e2c158..414264e697 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -155,7 +155,7 @@ EditorAbout::EditorAbout() {
Label *about_text = memnew(Label);
about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
about_text->set_text(String::utf8("\xc2\xa9 2007-2021 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2021 ") +
- TTR("Godot Engine contributors") + "\n");
+ TTR("Godot Engine contributors") + "\n");
version_info_vbc->add_child(about_text);
hbc->add_child(version_info_vbc);
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 2010ee01db..372d01d89a 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -1491,12 +1491,15 @@ void EditorExport::add_export_preset(const Ref<EditorExportPreset> &p_preset, in
}
String EditorExportPlatform::test_etc2() const {
+ // String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
+ // bool etc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc");
+ // bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2");
String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
bool etc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc");
bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2");
- if (driver == "GLES2" && !etc_supported) {
- return TTR("Target platform requires 'ETC' texture compression for GLES2. Enable 'Import Etc' in Project Settings.");
+ if (driver == "OpenGL3" && !etc_supported) {
+ return TTR("Target platform requires 'ETC' texture compression for OpenGL. Enable 'Import Etc' in Project Settings.");
} else if (driver == "Vulkan" && !etc2_supported) {
// FIXME: Review if this is true for Vulkan.
return TTR("Target platform requires 'ETC2' texture compression for Vulkan. Enable 'Import Etc 2' in Project Settings.");
@@ -1508,9 +1511,12 @@ String EditorExportPlatform::test_etc2_or_pvrtc() const {
String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2");
bool pvrtc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc");
+ // String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name");
+ // bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2");
+ // bool pvrtc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc");
- if (driver == "GLES2" && !pvrtc_supported) {
- return TTR("Target platform requires 'PVRTC' texture compression for GLES2. Enable 'Import Pvrtc' in Project Settings.");
+ if (driver == "OpenGL3" && !pvrtc_supported) {
+ return TTR("Target platform requires 'PVRTC' texture compression for OpenGL. Enable 'Import Pvrtc' in Project Settings.");
} else if (driver == "Vulkan" && !etc2_supported && !pvrtc_supported) {
// FIXME: Review if this is true for Vulkan.
return TTR("Target platform requires 'ETC2' or 'PVRTC' texture compression for Vulkan. Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings.");
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index c049db8ef6..8c3569df07 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -330,6 +330,153 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
return OK;
}
+void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods, bool &r_method_descrpitons) {
+ Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ class_desc->pop();
+ class_desc->pop();
+
+ class_desc->add_newline();
+ class_desc->push_font(doc_code_font);
+ class_desc->push_indent(1);
+ class_desc->push_table(2);
+ class_desc->set_table_column_expand(1, true);
+
+ bool any_previous = false;
+ for (int pass = 0; pass < 2; pass++) {
+ Vector<DocData::MethodDoc> m;
+
+ for (int i = 0; i < p_methods.size(); i++) {
+ const String &q = p_methods[i].qualifiers;
+ if ((pass == 0 && q.find("virtual") != -1) || (pass == 1 && q.find("virtual") == -1)) {
+ m.push_back(p_methods[i]);
+ }
+ }
+
+ if (any_previous && !m.is_empty()) {
+ class_desc->push_cell();
+ class_desc->pop(); //cell
+ class_desc->push_cell();
+ class_desc->pop(); //cell
+ }
+
+ String group_prefix;
+ for (int i = 0; i < m.size(); i++) {
+ const String new_prefix = m[i].name.substr(0, 3);
+ bool is_new_group = false;
+
+ if (i < m.size() - 1 && new_prefix == m[i + 1].name.substr(0, 3) && new_prefix != group_prefix) {
+ is_new_group = i > 0;
+ group_prefix = new_prefix;
+ } else if (group_prefix != "" && new_prefix != group_prefix) {
+ is_new_group = true;
+ group_prefix = "";
+ }
+
+ if (is_new_group && pass == 1) {
+ class_desc->push_cell();
+ class_desc->pop(); //cell
+ class_desc->push_cell();
+ class_desc->pop(); //cell
+ }
+
+ if (m[i].description != "" || m[i].errors_returned.size() > 0) {
+ r_method_descrpitons = true;
+ }
+
+ _add_method(m[i], true);
+ }
+
+ any_previous = !m.is_empty();
+ }
+
+ class_desc->pop(); //table
+ class_desc->pop();
+ class_desc->pop(); // font
+ class_desc->add_newline();
+ class_desc->add_newline();
+}
+
+void EditorHelp::_update_method_descriptions(const DocData::ClassDoc p_classdoc, const Vector<DocData::MethodDoc> p_methods, const String &p_method_type) {
+ Ref<Font> doc_font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
+ Ref<Font> doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
+ Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ String link_color_text = title_color.to_html(false);
+ class_desc->pop();
+ class_desc->pop();
+
+ class_desc->add_newline();
+ class_desc->add_newline();
+
+ for (int pass = 0; pass < 2; pass++) {
+ Vector<DocData::MethodDoc> methods_filtered;
+
+ for (int i = 0; i < p_methods.size(); i++) {
+ const String &q = p_methods[i].qualifiers;
+ if ((pass == 0 && q.find("virtual") != -1) || (pass == 1 && q.find("virtual") == -1)) {
+ methods_filtered.push_back(p_methods[i]);
+ }
+ }
+
+ for (int i = 0; i < methods_filtered.size(); i++) {
+ class_desc->push_font(doc_code_font);
+ _add_method(methods_filtered[i], false);
+ class_desc->pop();
+
+ class_desc->add_newline();
+ class_desc->add_newline();
+
+ class_desc->push_color(text_color);
+ class_desc->push_font(doc_font);
+ class_desc->push_indent(1);
+ if (methods_filtered[i].errors_returned.size()) {
+ class_desc->append_text(TTR("Error codes returned:"));
+ class_desc->add_newline();
+ class_desc->push_list(0, RichTextLabel::LIST_DOTS, false);
+ for (int j = 0; j < methods_filtered[i].errors_returned.size(); j++) {
+ if (j > 0) {
+ class_desc->add_newline();
+ }
+ int val = methods_filtered[i].errors_returned[j];
+ String text = itos(val);
+ for (int k = 0; k < CoreConstants::get_global_constant_count(); k++) {
+ if (CoreConstants::get_global_constant_value(k) == val && CoreConstants::get_global_constant_enum(k) == SNAME("Error")) {
+ text = CoreConstants::get_global_constant_name(k);
+ break;
+ }
+ }
+
+ class_desc->push_bold();
+ class_desc->append_text(text);
+ class_desc->pop();
+ }
+ class_desc->pop();
+ class_desc->add_newline();
+ class_desc->add_newline();
+ }
+ if (!methods_filtered[i].description.strip_edges().is_empty()) {
+ _add_text(DTR(methods_filtered[i].description));
+ } else {
+ class_desc->add_image(get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
+ class_desc->add_text(" ");
+ class_desc->push_color(comment_color);
+ if (p_classdoc.is_script_doc) {
+ class_desc->append_text(TTR("There is currently no description for this " + p_method_type + "."));
+ } else {
+ class_desc->append_text(TTR("There is currently no description for this " + p_method_type + ". Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text));
+ }
+ class_desc->pop();
+ }
+
+ class_desc->pop();
+ class_desc->pop();
+ class_desc->pop();
+ class_desc->add_newline();
+ class_desc->add_newline();
+ class_desc->add_newline();
+ }
+ }
+}
+
void EditorHelp::_update_doc() {
if (!doc->class_list.has(edited_class)) {
return;
@@ -622,7 +769,9 @@ void EditorHelp::_update_doc() {
}
// Methods overview
- bool method_descr = false;
+ bool constructor_descriptions = false;
+ bool method_descriptions = false;
+ bool operator_descriptions = false;
bool sort_methods = EditorSettings::get_singleton()->get("text_editor/help/sort_functions_alphabetically");
Vector<DocData::MethodDoc> methods;
@@ -640,81 +789,43 @@ void EditorHelp::_update_doc() {
methods.push_back(cd.methods[i]);
}
- if (methods.size()) {
+ if (!cd.constructors.is_empty()) {
if (sort_methods) {
- methods.sort();
+ cd.constructors.sort();
}
+ section_line.push_back(Pair<String, int>(TTR("Constructors"), class_desc->get_line_count() - 2));
+ class_desc->push_color(title_color);
+ class_desc->push_font(doc_title_font);
+ class_desc->add_text(TTR("Constructors"));
+ _update_method_list(cd.constructors, constructor_descriptions);
+ }
+
+ if (!methods.is_empty()) {
+ if (sort_methods) {
+ methods.sort();
+ }
section_line.push_back(Pair<String, int>(TTR("Methods"), class_desc->get_line_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Methods"));
- class_desc->pop();
- class_desc->pop();
-
- class_desc->add_newline();
- class_desc->push_font(doc_code_font);
- class_desc->push_indent(1);
- class_desc->push_table(2);
- class_desc->set_table_column_expand(1, true);
-
- bool any_previous = false;
- for (int pass = 0; pass < 2; pass++) {
- Vector<DocData::MethodDoc> m;
-
- for (int i = 0; i < methods.size(); i++) {
- const String &q = methods[i].qualifiers;
- if ((pass == 0 && q.find("virtual") != -1) || (pass == 1 && q.find("virtual") == -1)) {
- m.push_back(methods[i]);
- }
- }
-
- if (any_previous && !m.is_empty()) {
- class_desc->push_cell();
- class_desc->pop(); //cell
- class_desc->push_cell();
- class_desc->pop(); //cell
- }
-
- String group_prefix;
- for (int i = 0; i < m.size(); i++) {
- const String new_prefix = m[i].name.substr(0, 3);
- bool is_new_group = false;
-
- if (i < m.size() - 1 && new_prefix == m[i + 1].name.substr(0, 3) && new_prefix != group_prefix) {
- is_new_group = i > 0;
- group_prefix = new_prefix;
- } else if (group_prefix != "" && new_prefix != group_prefix) {
- is_new_group = true;
- group_prefix = "";
- }
-
- if (is_new_group && pass == 1) {
- class_desc->push_cell();
- class_desc->pop(); //cell
- class_desc->push_cell();
- class_desc->pop(); //cell
- }
-
- if (m[i].description != "" || m[i].errors_returned.size() > 0) {
- method_descr = true;
- }
-
- _add_method(m[i], true);
- }
+ _update_method_list(methods, method_descriptions);
+ }
- any_previous = !m.is_empty();
+ if (!cd.operators.is_empty()) {
+ if (sort_methods) {
+ cd.operators.sort();
}
- class_desc->pop(); //table
- class_desc->pop();
- class_desc->pop(); // font
- class_desc->add_newline();
- class_desc->add_newline();
+ section_line.push_back(Pair<String, int>(TTR("Operators"), class_desc->get_line_count() - 2));
+ class_desc->push_color(title_color);
+ class_desc->push_font(doc_title_font);
+ class_desc->add_text(TTR("Operators"));
+ _update_method_list(cd.operators, operator_descriptions);
}
// Theme properties
- if (cd.theme_properties.size()) {
+ if (!cd.theme_properties.is_empty()) {
section_line.push_back(Pair<String, int>(TTR("Theme Properties"), class_desc->get_line_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
@@ -775,7 +886,7 @@ void EditorHelp::_update_doc() {
}
// Signals
- if (cd.signals.size()) {
+ if (!cd.signals.is_empty()) {
if (sort_methods) {
cd.signals.sort();
}
@@ -844,7 +955,7 @@ void EditorHelp::_update_doc() {
}
// Constants and enums
- if (cd.constants.size()) {
+ if (!cd.constants.is_empty()) {
Map<String, Vector<DocData::ConstantDoc>> enums;
Vector<DocData::ConstantDoc> constants;
@@ -1195,86 +1306,31 @@ void EditorHelp::_update_doc() {
}
}
+ // Constructor descriptions
+ if (constructor_descriptions) {
+ section_line.push_back(Pair<String, int>(TTR("Constructor Descriptions"), class_desc->get_line_count() - 2));
+ class_desc->push_color(title_color);
+ class_desc->push_font(doc_title_font);
+ class_desc->add_text(TTR("Constructor Descriptions"));
+ _update_method_descriptions(cd, cd.constructors, "constructor");
+ }
+
// Method descriptions
- if (method_descr) {
+ if (method_descriptions) {
section_line.push_back(Pair<String, int>(TTR("Method Descriptions"), class_desc->get_line_count() - 2));
class_desc->push_color(title_color);
class_desc->push_font(doc_title_font);
class_desc->add_text(TTR("Method Descriptions"));
- class_desc->pop();
- class_desc->pop();
-
- class_desc->add_newline();
- class_desc->add_newline();
-
- for (int pass = 0; pass < 2; pass++) {
- Vector<DocData::MethodDoc> methods_filtered;
-
- for (int i = 0; i < methods.size(); i++) {
- const String &q = methods[i].qualifiers;
- if ((pass == 0 && q.find("virtual") != -1) || (pass == 1 && q.find("virtual") == -1)) {
- methods_filtered.push_back(methods[i]);
- }
- }
-
- for (int i = 0; i < methods_filtered.size(); i++) {
- class_desc->push_font(doc_code_font);
- _add_method(methods_filtered[i], false);
- class_desc->pop();
-
- class_desc->add_newline();
- class_desc->add_newline();
-
- class_desc->push_color(text_color);
- class_desc->push_font(doc_font);
- class_desc->push_indent(1);
- if (methods_filtered[i].errors_returned.size()) {
- class_desc->append_text(TTR("Error codes returned:"));
- class_desc->add_newline();
- class_desc->push_list(0, RichTextLabel::LIST_DOTS, false);
- for (int j = 0; j < methods_filtered[i].errors_returned.size(); j++) {
- if (j > 0) {
- class_desc->add_newline();
- }
- int val = methods_filtered[i].errors_returned[j];
- String text = itos(val);
- for (int k = 0; k < CoreConstants::get_global_constant_count(); k++) {
- if (CoreConstants::get_global_constant_value(k) == val && CoreConstants::get_global_constant_enum(k) == SNAME("Error")) {
- text = CoreConstants::get_global_constant_name(k);
- break;
- }
- }
-
- class_desc->push_bold();
- class_desc->append_text(text);
- class_desc->pop();
- }
- class_desc->pop();
- class_desc->add_newline();
- class_desc->add_newline();
- }
- if (!methods_filtered[i].description.strip_edges().is_empty()) {
- _add_text(DTR(methods_filtered[i].description));
- } else {
- class_desc->add_image(get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
- class_desc->add_text(" ");
- class_desc->push_color(comment_color);
- if (cd.is_script_doc) {
- class_desc->append_text(TTR("There is currently no description for this method."));
- } else {
- class_desc->append_text(TTR("There is currently no description for this method. Please help us by [color=$color][url=$url]contributing one[/url][/color]!").replace("$url", CONTRIBUTE_URL).replace("$color", link_color_text));
- }
- class_desc->pop();
- }
+ _update_method_descriptions(cd, methods, "method");
+ }
- class_desc->pop();
- class_desc->pop();
- class_desc->pop();
- class_desc->add_newline();
- class_desc->add_newline();
- class_desc->add_newline();
- }
- }
+ // Operator descriptions
+ if (operator_descriptions) {
+ section_line.push_back(Pair<String, int>(TTR("Operator Descriptions"), class_desc->get_line_count() - 2));
+ class_desc->push_color(title_color);
+ class_desc->push_font(doc_title_font);
+ class_desc->add_text(TTR("Operator Descriptions"));
+ _update_method_descriptions(cd, cd.operators, "operator");
}
scroll_locked = false;
}
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 46605b6763..c0f3f66505 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -152,6 +152,8 @@ class EditorHelp : public VBoxContainer {
Error _goto_desc(const String &p_class, int p_vscr = -1);
//void _update_history_buttons();
+ void _update_method_list(const Vector<DocData::MethodDoc> p_methods, bool &r_method_descrpitons);
+ void _update_method_descriptions(const DocData::ClassDoc p_classdoc, const Vector<DocData::MethodDoc> p_methods, const String &p_method_type);
void _update_doc();
void _request_help(const String &p_string);
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index e56b10720d..8504745b03 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -226,7 +226,9 @@ EditorHelpSearch::EditorHelpSearch() {
filter_combo->add_item(TTR("Display All"), SEARCH_ALL);
filter_combo->add_separator();
filter_combo->add_item(TTR("Classes Only"), SEARCH_CLASSES);
+ filter_combo->add_item(TTR("Constructors Only"), SEARCH_CONSTRUCTORS);
filter_combo->add_item(TTR("Methods Only"), SEARCH_METHODS);
+ filter_combo->add_item(TTR("Operators Only"), SEARCH_OPERATORS);
filter_combo->add_item(TTR("Signals Only"), SEARCH_SIGNALS);
filter_combo->add_item(TTR("Constants Only"), SEARCH_CONSTANTS);
filter_combo->add_item(TTR("Properties Only"), SEARCH_PROPERTIES);
@@ -334,6 +336,17 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
// Match members if the term is long enough.
if (term.length() > 1) {
+ if (search_flags & SEARCH_CONSTRUCTORS) {
+ for (int i = 0; i < class_doc.constructors.size(); i++) {
+ String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.constructors[i].name : class_doc.constructors[i].name.to_lower();
+ if (method_name.find(term) > -1 ||
+ (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
+ (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
+ (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
+ match.constructors.push_back(const_cast<DocData::MethodDoc *>(&class_doc.constructors[i]));
+ }
+ }
+ }
if (search_flags & SEARCH_METHODS) {
for (int i = 0; i < class_doc.methods.size(); i++) {
String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower();
@@ -345,6 +358,17 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
}
}
}
+ if (search_flags & SEARCH_OPERATORS) {
+ for (int i = 0; i < class_doc.operators.size(); i++) {
+ String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.operators[i].name : class_doc.operators[i].name.to_lower();
+ if (method_name.find(term) > -1 ||
+ (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
+ (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
+ (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
+ match.operators.push_back(const_cast<DocData::MethodDoc *>(&class_doc.operators[i]));
+ }
+ }
+ }
if (search_flags & SEARCH_SIGNALS) {
for (int i = 0; i < class_doc.signals.size(); i++) {
if (_match_string(term, class_doc.signals[i].name)) {
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index bc57c0e3c6..7285f76c01 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -43,12 +43,14 @@ class EditorHelpSearch : public ConfirmationDialog {
enum SearchFlags {
SEARCH_CLASSES = 1 << 0,
- SEARCH_METHODS = 1 << 1,
- SEARCH_SIGNALS = 1 << 2,
- SEARCH_CONSTANTS = 1 << 3,
- SEARCH_PROPERTIES = 1 << 4,
- SEARCH_THEME_ITEMS = 1 << 5,
- SEARCH_ALL = SEARCH_CLASSES | SEARCH_METHODS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS,
+ SEARCH_CONSTRUCTORS = 1 << 1,
+ SEARCH_METHODS = 1 << 2,
+ SEARCH_OPERATORS = 1 << 3,
+ SEARCH_SIGNALS = 1 << 4,
+ SEARCH_CONSTANTS = 1 << 5,
+ SEARCH_PROPERTIES = 1 << 6,
+ SEARCH_THEME_ITEMS = 1 << 7,
+ SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS,
SEARCH_CASE_SENSITIVE = 1 << 29,
SEARCH_SHOW_HIERARCHY = 1 << 30
};
@@ -99,7 +101,9 @@ class EditorHelpSearch::Runner : public RefCounted {
struct ClassMatch {
DocData::ClassDoc *doc;
bool name = false;
+ Vector<DocData::MethodDoc *> constructors;
Vector<DocData::MethodDoc *> methods;
+ Vector<DocData::MethodDoc *> operators;
Vector<DocData::MethodDoc *> signals;
Vector<DocData::ConstantDoc *> constants;
Vector<DocData::PropertyDoc *> properties;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index b4980fe074..bb4a05efba 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -144,7 +144,6 @@
#include "editor/plugins/gpu_particles_collision_sdf_editor_plugin.h"
#include "editor/plugins/gradient_editor_plugin.h"
#include "editor/plugins/input_event_editor_plugin.h"
-#include "editor/plugins/item_list_editor_plugin.h"
#include "editor/plugins/light_occluder_2d_editor_plugin.h"
#include "editor/plugins/lightmap_gi_editor_plugin.h"
#include "editor/plugins/line_2d_editor_plugin.h"
@@ -590,6 +589,11 @@ void EditorNode::_notification(int p_what) {
settings_changed = false;
emit_signal(SNAME("project_settings_changed"));
}
+
+ ResourceImporterTexture::get_singleton()->update_imports();
+
+ // if using a main thread only renderer, we need to update the resource previews
+ EditorResourcePreview::get_singleton()->update();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -2904,8 +2908,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
OS::get_singleton()->shell_open("https://godotengine.org/donate");
} break;
- case SET_VIDEO_DRIVER_SAVE_AND_RESTART: {
- ProjectSettings::get_singleton()->set("rendering/driver/driver_name", video_driver_request);
+ // case SET_VIDEO_DRIVER_SAVE_AND_RESTART: {
+ // ProjectSettings::get_singleton()->set("rendering/driver/driver_name", video_driver_request);
+ // save_all_scenes();
+ // restart_editor();
+ // } break;
+ case SET_RENDERING_DRIVER_SAVE_AND_RESTART: {
+ ProjectSettings::get_singleton()->set("rendering/driver/driver_name", rendering_driver_request);
ProjectSettings::get_singleton()->save();
save_all_scenes();
@@ -3050,7 +3059,7 @@ void EditorNode::_discard_changes(const String &p_str) {
args.push_back(exec.get_base_dir());
args.push_back("--project-manager");
- Error err = OS::get_singleton()->create_process(exec, args);
+ Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
} break;
}
@@ -4965,9 +4974,9 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
return;
}
- bool unsaved = (p_tab == editor_data.get_edited_scene()) ?
- saved_version != editor_data.get_undo_redo().get_version() :
- editor_data.get_scene_version(p_tab) != 0;
+ bool unsaved = (p_tab == editor_data.get_edited_scene())
+ ? saved_version != editor_data.get_undo_redo().get_version()
+ : editor_data.get_scene_version(p_tab) != 0;
if (unsaved) {
save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene->get_scene_file_path() != "" ? scene->get_scene_file_path() : "unsaved scene"));
@@ -5411,8 +5420,7 @@ void EditorNode::_global_menu_new_window(const Variant &p_tag) {
if (OS::get_singleton()->get_main_loop()) {
List<String> args;
args.push_back("-p");
- String exec = OS::get_singleton()->get_executable_path();
- OS::get_singleton()->create_process(exec, args);
+ OS::get_singleton()->create_instance(args);
}
}
@@ -5586,17 +5594,16 @@ void EditorNode::_bottom_panel_raise_toggled(bool p_pressed) {
top_split->set_visible(!p_pressed);
}
-void EditorNode::_update_video_driver_color() {
- // TODO: Probably should de-hardcode this and add to editor settings.
- if (video_driver->get_text() == "GLES2") {
- video_driver->add_theme_color_override("font_color", Color::hex(0x5586a4ff));
- } else if (video_driver->get_text() == "Vulkan") {
- video_driver->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
+void EditorNode::_update_rendering_driver_color() {
+ if (rendering_driver->get_text() == "opengl3") {
+ rendering_driver->add_theme_color_override("font_color", Color::hex(0x5586a4ff));
+ } else if (rendering_driver->get_text() == "vulkan") {
+ rendering_driver->add_theme_color_override("font_color", theme_base->get_theme_color("vulkan_color", "Editor"));
}
}
-void EditorNode::_video_driver_selected(int p_which) {
- String driver = video_driver->get_item_metadata(p_which);
+void EditorNode::_rendering_driver_selected(int p_which) {
+ String driver = rendering_driver->get_item_metadata(p_which);
String current = ""; // OS::get_singleton()->get_video_driver_name(OS::get_singleton()->get_current_video_driver());
@@ -5604,10 +5611,10 @@ void EditorNode::_video_driver_selected(int p_which) {
return;
}
- video_driver_request = driver;
+ rendering_driver_request = driver;
video_restart_dialog->popup_centered();
- video_driver->select(video_driver_current);
- _update_video_driver_color();
+ rendering_driver->select(rendering_driver_current);
+ _update_rendering_driver_color();
}
void EditorNode::_resource_saved(RES p_resource, const String &p_path) {
@@ -6228,7 +6235,7 @@ EditorNode::EditorNode() {
scene_tabs->set_drag_to_rearrange_enabled(true);
scene_tabs->connect("tab_changed", callable_mp(this, &EditorNode::_scene_tab_changed));
scene_tabs->connect("tab_rmb_clicked", callable_mp(this, &EditorNode::_scene_tab_script_edited));
- scene_tabs->connect("tab_closed", callable_mp(this, &EditorNode::_scene_tab_closed), varray(SCENE_TAB_CLOSE));
+ scene_tabs->connect("tab_close_pressed", callable_mp(this, &EditorNode::_scene_tab_closed), varray(SCENE_TAB_CLOSE));
scene_tabs->connect("tab_hovered", callable_mp(this, &EditorNode::_scene_tab_hovered));
scene_tabs->connect("mouse_exited", callable_mp(this, &EditorNode::_scene_tab_exit));
scene_tabs->connect("gui_input", callable_mp(this, &EditorNode::_scene_tab_input));
@@ -6611,40 +6618,50 @@ EditorNode::EditorNode() {
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
menu_hb->add_child(right_menu_hb);
- // Toggle for video driver
- video_driver = memnew(OptionButton);
- video_driver->set_focus_mode(Control::FOCUS_NONE);
- video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected));
- video_driver->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
- video_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts")));
- // TODO: Show again when OpenGL is ported.
- video_driver->set_visible(false);
- right_menu_hb->add_child(video_driver);
-
-#ifndef _MSC_VER
-#warning needs to be reimplemented
-#endif
-#if 0
- String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/driver/driver_name"].hint_string;
- String current_video_driver = OS::get_singleton()->get_video_driver_name(OS::get_singleton()->get_current_video_driver());
- video_driver_current = 0;
- for (int i = 0; i < video_drivers.get_slice_count(","); i++) {
- String driver = video_drivers.get_slice(",", i);
- video_driver->add_item(driver);
- video_driver->set_item_metadata(i, driver);
+ rendering_driver = memnew(OptionButton);
+
+ // Hide the renderer selection dropdown until OpenGL support is more mature.
+ // The renderer can still be changed in the project settings or using `--rendering-driver opengl3`.
+ rendering_driver->set_visible(false);
+
+ rendering_driver->set_flat(true);
+ rendering_driver->set_focus_mode(Control::FOCUS_NONE);
+ rendering_driver->connect("item_selected", callable_mp(this, &EditorNode::_rendering_driver_selected));
+ rendering_driver->add_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts"));
+ rendering_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size("bold_size", "EditorFonts"));
+
+ right_menu_hb->add_child(rendering_driver);
+
+ // Only display the render drivers that are available for this display driver.
+ int display_driver_idx = OS::get_singleton()->get_display_driver_id();
+ Vector<String> render_drivers = DisplayServer::get_create_function_rendering_drivers(display_driver_idx);
+ String current_rendering_driver = OS::get_singleton()->get_current_rendering_driver_name();
- if (current_video_driver == driver) {
- video_driver->select(i);
- video_driver_current = i;
+ // As we are doing string comparisons, keep in standard case to prevent problems with capitals
+ // "vulkan" in particular uses lowercase "v" in the code, and uppercase in the UI.
+ current_rendering_driver = current_rendering_driver.to_lower();
+
+ for (int i = 0; i < render_drivers.size(); i++) {
+ String driver = render_drivers[i];
+
+ // Add the driver to the UI.
+ rendering_driver->add_item(driver);
+ rendering_driver->set_item_metadata(i, driver);
+
+ // Lowercase for standard comparison.
+ driver = driver.to_lower();
+
+ if (current_rendering_driver == driver) {
+ rendering_driver->select(i);
+ rendering_driver_current = i;
}
}
+ _update_rendering_driver_color();
- _update_video_driver_color();
-#endif
video_restart_dialog = memnew(ConfirmationDialog);
video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
video_restart_dialog->get_ok_button()->set_text(TTR("Save & Restart"));
- video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SET_VIDEO_DRIVER_SAVE_AND_RESTART));
+ video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SET_RENDERING_DRIVER_SAVE_AND_RESTART));
gui_base->add_child(video_restart_dialog);
progress_hb = memnew(BackgroundProgress);
@@ -6960,7 +6977,6 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(CPUParticles2DEditorPlugin(this)));
add_editor_plugin(memnew(CPUParticles3DEditorPlugin(this)));
add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this)));
- add_editor_plugin(memnew(ItemListEditorPlugin(this)));
add_editor_plugin(memnew(Polygon3DEditorPlugin(this)));
add_editor_plugin(memnew(CollisionPolygon2DEditorPlugin(this)));
add_editor_plugin(memnew(TilesEditorPlugin(this)));
@@ -7017,6 +7033,10 @@ EditorNode::EditorNode() {
spatial_mat_convert.instantiate();
resource_conversion_plugins.push_back(spatial_mat_convert);
+ Ref<ORMMaterial3DConversionPlugin> orm_mat_convert;
+ orm_mat_convert.instantiate();
+ resource_conversion_plugins.push_back(orm_mat_convert);
+
Ref<CanvasItemMaterialConversionPlugin> canvas_item_mat_convert;
canvas_item_mat_convert.instantiate();
resource_conversion_plugins.push_back(canvas_item_mat_convert);
@@ -7037,6 +7057,10 @@ EditorNode::EditorNode() {
physical_sky_mat_convert.instantiate();
resource_conversion_plugins.push_back(physical_sky_mat_convert);
+ Ref<FogMaterialConversionPlugin> fog_mat_convert;
+ fog_mat_convert.instantiate();
+ resource_conversion_plugins.push_back(fog_mat_convert);
+
Ref<VisualShaderConversionPlugin> vshader_convert;
vshader_convert.instantiate();
resource_conversion_plugins.push_back(vshader_convert);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 03e5146d98..98aa4b697c 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -206,7 +206,7 @@ private:
HELP_ABOUT,
HELP_SUPPORT_GODOT_DEVELOPMENT,
- SET_VIDEO_DRIVER_SAVE_AND_RESTART,
+ SET_RENDERING_DRIVER_SAVE_AND_RESTART,
GLOBAL_NEW_WINDOW,
GLOBAL_SCENE,
@@ -222,14 +222,14 @@ private:
Control *theme_base;
Control *gui_base;
VBoxContainer *main_vbox;
- OptionButton *video_driver;
+ OptionButton *rendering_driver;
ConfirmationDialog *video_restart_dialog;
- int video_driver_current;
- String video_driver_request;
- void _video_driver_selected(int);
- void _update_video_driver_color();
+ int rendering_driver_current;
+ String rendering_driver_request;
+ void _rendering_driver_selected(int);
+ void _update_rendering_driver_color();
// Split containers
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 6a36304ba4..e679222567 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -3237,11 +3237,11 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
return editor;
} else if (p_hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
- p_hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
- p_hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
- p_hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
- p_hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
- p_hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
+ p_hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
+ p_hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
+ p_hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
+ p_hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
+ p_hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
EditorPropertyLayers::LayerType lt = EditorPropertyLayers::LAYER_RENDER_2D;
switch (p_hint) {
case PROPERTY_HINT_LAYERS_2D_RENDER:
@@ -3336,13 +3336,13 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
}
return editor;
} else if (p_hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE ||
- p_hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE ||
- p_hint == PROPERTY_HINT_METHOD_OF_INSTANCE ||
- p_hint == PROPERTY_HINT_METHOD_OF_SCRIPT ||
- p_hint == PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE ||
- p_hint == PROPERTY_HINT_PROPERTY_OF_BASE_TYPE ||
- p_hint == PROPERTY_HINT_PROPERTY_OF_INSTANCE ||
- p_hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) {
+ p_hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE ||
+ p_hint == PROPERTY_HINT_METHOD_OF_INSTANCE ||
+ p_hint == PROPERTY_HINT_METHOD_OF_SCRIPT ||
+ p_hint == PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE ||
+ p_hint == PROPERTY_HINT_PROPERTY_OF_BASE_TYPE ||
+ p_hint == PROPERTY_HINT_PROPERTY_OF_INSTANCE ||
+ p_hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) {
EditorPropertyMember *editor = memnew(EditorPropertyMember);
EditorPropertyMember::Type type = EditorPropertyMember::MEMBER_METHOD_OF_BASE_TYPE;
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 9b5dc8851c..a3b6f6e59b 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -855,6 +855,7 @@ void EditorPropertyDictionary::update_property() {
object->set_dict(dict);
VBoxContainer *add_vbox = nullptr;
+ double default_float_step = EDITOR_GET("interface/inspector/default_float_step");
for (int i = 0; i < amount + 2; i++) {
String prop_name;
@@ -894,7 +895,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::FLOAT: {
EditorPropertyFloat *editor = memnew(EditorPropertyFloat);
- editor->setup(-100000, 100000, 0.001, true, false, true, true);
+ editor->setup(-100000, 100000, default_float_step, true, false, true, true);
prop = editor;
} break;
case Variant::STRING: {
@@ -905,7 +906,7 @@ void EditorPropertyDictionary::update_property() {
// Math types.
case Variant::VECTOR2: {
EditorPropertyVector2 *editor = memnew(EditorPropertyVector2);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
@@ -917,7 +918,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::RECT2: {
EditorPropertyRect2 *editor = memnew(EditorPropertyRect2);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
@@ -929,7 +930,7 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::VECTOR3: {
EditorPropertyVector3 *editor = memnew(EditorPropertyVector3);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
@@ -941,37 +942,37 @@ void EditorPropertyDictionary::update_property() {
} break;
case Variant::TRANSFORM2D: {
EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
case Variant::PLANE: {
EditorPropertyPlane *editor = memnew(EditorPropertyPlane);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
case Variant::QUATERNION: {
EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
case Variant::AABB: {
EditorPropertyAABB *editor = memnew(EditorPropertyAABB);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
case Variant::BASIS: {
EditorPropertyBasis *editor = memnew(EditorPropertyBasis);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
case Variant::TRANSFORM3D: {
EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D);
- editor->setup(-100000, 100000, 0.001, true);
+ editor->setup(-100000, 100000, default_float_step, true);
prop = editor;
} break;
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 8783fe4fc0..e9c0b40268 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -210,126 +210,130 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
}
-void EditorResourcePreview::_thread() {
- exited.clear();
- while (!exit.is_set()) {
- preview_sem.wait();
- preview_mutex.lock();
-
- if (queue.size()) {
- QueueItem item = queue.front()->get();
- queue.pop_front();
-
- if (cache.has(item.path)) {
- //already has it because someone loaded it, just let it know it's ready
- String path = item.path;
- if (item.resource.is_valid()) {
- path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
- }
-
- _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
-
- preview_mutex.unlock();
- } else {
- preview_mutex.unlock();
+void EditorResourcePreview::_iterate() {
+ preview_mutex.lock();
+
+ if (queue.size()) {
+ QueueItem item = queue.front()->get();
+ queue.pop_front();
+
+ if (cache.has(item.path)) {
+ //already has it because someone loaded it, just let it know it's ready
+ String path = item.path;
+ if (item.resource.is_valid()) {
+ path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
+ }
- Ref<ImageTexture> texture;
- Ref<ImageTexture> small_texture;
+ _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
+ preview_mutex.unlock();
+ } else {
+ preview_mutex.unlock();
- if (item.resource.is_valid()) {
- _generate_preview(texture, small_texture, item, String());
+ Ref<ImageTexture> texture;
+ Ref<ImageTexture> small_texture;
- //adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
- _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
+ int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ thumbnail_size *= EDSCALE;
- } else {
- String temp_path = EditorPaths::get_singleton()->get_cache_dir();
- String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ if (item.resource.is_valid()) {
+ _generate_preview(texture, small_texture, item, String());
- //does not have it, try to load a cached thumbnail
+ //adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
+ _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
- String file = cache_base + ".txt";
- FileAccess *f = FileAccess::open(file, FileAccess::READ);
- if (!f) {
- // No cache found, generate
- _generate_preview(texture, small_texture, item, cache_base);
- } else {
- uint64_t modtime = FileAccess::get_modified_time(item.path);
- int tsize = f->get_line().to_int();
- bool has_small_texture = f->get_line().to_int();
- uint64_t last_modtime = f->get_line().to_int();
+ } else {
+ String temp_path = EditorPaths::get_singleton()->get_cache_dir();
+ String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
+ cache_base = temp_path.plus_file("resthumb-" + cache_base);
- bool cache_valid = true;
+ //does not have it, try to load a cached thumbnail
- if (tsize != thumbnail_size) {
+ String file = cache_base + ".txt";
+ FileAccess *f = FileAccess::open(file, FileAccess::READ);
+ if (!f) {
+ // No cache found, generate
+ _generate_preview(texture, small_texture, item, cache_base);
+ } else {
+ uint64_t modtime = FileAccess::get_modified_time(item.path);
+ int tsize = f->get_line().to_int();
+ bool has_small_texture = f->get_line().to_int();
+ uint64_t last_modtime = f->get_line().to_int();
+
+ bool cache_valid = true;
+
+ if (tsize != thumbnail_size) {
+ cache_valid = false;
+ memdelete(f);
+ } else if (last_modtime != modtime) {
+ String last_md5 = f->get_line();
+ String md5 = FileAccess::get_md5(item.path);
+ memdelete(f);
+
+ if (last_md5 != md5) {
cache_valid = false;
- memdelete(f);
- } else if (last_modtime != modtime) {
- String last_md5 = f->get_line();
- String md5 = FileAccess::get_md5(item.path);
- memdelete(f);
- if (last_md5 != md5) {
- cache_valid = false;
+ } else {
+ //update modified time
+ f = FileAccess::open(file, FileAccess::WRITE);
+ if (!f) {
+ // Not returning as this would leave the thread hanging and would require
+ // some proper cleanup/disabling of resource preview generation.
+ ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
} else {
- //update modified time
-
- f = FileAccess::open(file, FileAccess::WRITE);
- if (!f) {
- // Not returning as this would leave the thread hanging and would require
- // some proper cleanup/disabling of resource preview generation.
- ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
- } else {
- f->store_line(itos(thumbnail_size));
- f->store_line(itos(has_small_texture));
- f->store_line(itos(modtime));
- f->store_line(md5);
- memdelete(f);
- }
+ f->store_line(itos(thumbnail_size));
+ f->store_line(itos(has_small_texture));
+ f->store_line(itos(modtime));
+ f->store_line(md5);
+ memdelete(f);
}
- } else {
- memdelete(f);
}
+ } else {
+ memdelete(f);
+ }
- if (cache_valid) {
- Ref<Image> img;
- img.instantiate();
- Ref<Image> small_img;
- small_img.instantiate();
+ if (cache_valid) {
+ Ref<Image> img;
+ img.instantiate();
+ Ref<Image> small_img;
+ small_img.instantiate();
- if (img->load(cache_base + ".png") != OK) {
- cache_valid = false;
- } else {
- texture.instantiate();
- texture->create_from_image(img);
-
- if (has_small_texture) {
- if (small_img->load(cache_base + "_small.png") != OK) {
- cache_valid = false;
- } else {
- small_texture.instantiate();
- small_texture->create_from_image(small_img);
- }
+ if (img->load(cache_base + ".png") != OK) {
+ cache_valid = false;
+ } else {
+ texture.instantiate();
+ texture->create_from_image(img);
+
+ if (has_small_texture) {
+ if (small_img->load(cache_base + "_small.png") != OK) {
+ cache_valid = false;
+ } else {
+ small_texture.instantiate();
+ small_texture->create_from_image(small_img);
}
}
}
+ }
- if (!cache_valid) {
- _generate_preview(texture, small_texture, item, cache_base);
- }
+ if (!cache_valid) {
+ _generate_preview(texture, small_texture, item, cache_base);
}
- _preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
}
+ _preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
}
-
- } else {
- preview_mutex.unlock();
}
+
+ } else {
+ preview_mutex.unlock();
+ }
+}
+
+void EditorResourcePreview::_thread() {
+ exited.clear();
+ while (!exit.is_set()) {
+ preview_sem.wait();
+ _iterate();
}
exited.set();
}
@@ -429,8 +433,12 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
}
void EditorResourcePreview::start() {
- ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
- thread.start(_thread_func, this);
+ if (OS::get_singleton()->get_render_main_thread_mode() == OS::RENDER_ANY_THREAD) {
+ ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
+ thread.start(_thread_func, this);
+ } else {
+ _mainthread_only = true;
+ }
}
void EditorResourcePreview::stop() {
@@ -453,3 +461,18 @@ EditorResourcePreview::EditorResourcePreview() {
EditorResourcePreview::~EditorResourcePreview() {
stop();
}
+
+void EditorResourcePreview::update() {
+ if (!_mainthread_only) {
+ return;
+ }
+
+ if (!exit.is_set()) {
+ // no need to even lock the mutex if the size is zero
+ // there is no problem if queue.size() is wrong, even if
+ // there was a race condition.
+ if (queue.size()) {
+ _iterate();
+ }
+ }
+}
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index ea16c8fde0..9d1f269661 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -81,6 +81,11 @@ class EditorResourcePreview : public Node {
SafeFlag exit;
SafeFlag exited;
+ // when running from GLES, we want to run the previews
+ // in the main thread using an update, rather than create
+ // a separate thread
+ bool _mainthread_only = false;
+
struct Item {
Ref<Texture2D> preview;
Ref<Texture2D> small_preview;
@@ -98,6 +103,7 @@ class EditorResourcePreview : public Node {
static void _thread_func(void *ud);
void _thread();
+ void _iterate();
Vector<Ref<EditorResourcePreviewGenerator>> preview_generators;
@@ -119,6 +125,9 @@ public:
void start();
void stop();
+ // for single threaded mode
+ void update();
+
EditorResourcePreview();
~EditorResourcePreview();
};
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 8a7ec9aa82..d7daa0c750 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -236,7 +236,7 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
int instances = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_instances", 1);
for (int i = 0; i < instances; i++) {
OS::ProcessID pid = 0;
- Error err = OS::get_singleton()->create_process(exec, args, &pid);
+ Error err = OS::get_singleton()->create_instance(args, &pid);
ERR_FAIL_COND_V(err, err);
pids.push_back(pid);
}
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index ec90af1bcc..82b5ec5ca1 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -225,7 +225,8 @@ void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) {
set_value(last_value + real_step);
}
- value_input->set_text(get_text_value());
+ value_input_dirty = true;
+ set_process_internal(true);
} break;
case KEY_DOWN: {
_evaluate_input_text();
@@ -238,7 +239,8 @@ void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) {
set_value(last_value - real_step);
}
- value_input->set_text(get_text_value());
+ value_input_dirty = true;
+ set_process_internal(true);
} break;
}
}
@@ -424,6 +426,14 @@ void EditorSpinSlider::_notification(int p_what) {
_update_value_input_stylebox();
break;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ if (value_input_dirty) {
+ value_input_dirty = false;
+ value_input->set_text(get_text_value());
+ }
+ set_process_internal(false);
+ break;
+
case NOTIFICATION_DRAW:
_draw_spin_slider();
break;
diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h
index 7e10764491..68448b3240 100644
--- a/editor/editor_spin_slider.h
+++ b/editor/editor_spin_slider.h
@@ -66,6 +66,7 @@ class EditorSpinSlider : public Range {
Popup *value_input_popup = nullptr;
LineEdit *value_input = nullptr;
bool value_input_just_closed = false;
+ bool value_input_dirty = false;
void _grabber_gui_input(const Ref<InputEvent> &p_event);
void _value_input_closed();
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 9de0ea40fe..22da12b59b 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -172,10 +172,11 @@ void EditorToaster::_error_handler(void *p_self, const char *p_func, const char
}
}
- if (p_type == ERR_HANDLER_WARNING) {
- EditorToaster::get_singleton()->popup_str(err_str, SEVERITY_WARNING, tooltip_str);
+ Severity severity = (p_type == ERR_HANDLER_WARNING) ? SEVERITY_WARNING : SEVERITY_ERROR;
+ if (Thread::get_caller_id() != Thread::get_main_id()) {
+ EditorToaster::get_singleton()->call_deferred(SNAME("popup_str"), err_str, severity, tooltip_str);
} else {
- EditorToaster::get_singleton()->popup_str(err_str, SEVERITY_ERROR, tooltip_str);
+ EditorToaster::get_singleton()->popup_str(err_str, severity, tooltip_str);
}
}
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index cdf0f6e391..f2a3aa3b44 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1371,7 +1371,7 @@ void FileSystemDock::_make_dir_confirm() {
EditorNode::get_singleton()->show_warning(TTR("No name provided."));
return;
} else if (dir_name.find("/") != -1 || dir_name.find("\\") != -1 || dir_name.find(":") != -1 || dir_name.find("*") != -1 ||
- dir_name.find("|") != -1 || dir_name.find(">") != -1 || dir_name.ends_with(".") || dir_name.ends_with(" ")) {
+ dir_name.find("|") != -1 || dir_name.find(">") != -1 || dir_name.ends_with(".") || dir_name.ends_with(" ")) {
EditorNode::get_singleton()->show_warning(TTR("Provided name contains invalid characters."));
return;
}
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 6ed12c31ff..56356ff25b 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -47,13 +47,13 @@
const char *FindInFiles::SIGNAL_RESULT_FOUND = "result_found";
const char *FindInFiles::SIGNAL_FINISHED = "finished";
-// TODO Would be nice in Vector and Vectors
+// TODO: Would be nice in Vector and Vectors.
template <typename T>
inline void pop_back(T &container) {
container.resize(container.size() - 1);
}
-// TODO Copied from TextEdit private, would be nice to extract it in a single place
+// TODO: Copied from TextEdit private, would be nice to extract it in a single place.
static bool is_text_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
@@ -125,7 +125,7 @@ void FindInFiles::start() {
return;
}
- // Init search
+ // Init search.
_current_dir = "";
PackedStringArray init_folder;
init_folder.push_back(_root_dir);
@@ -145,14 +145,14 @@ void FindInFiles::stop() {
}
void FindInFiles::_process() {
- // This part can be moved to a thread if needed
+ // This part can be moved to a thread if needed.
OS &os = *OS::get_singleton();
uint64_t time_before = os.get_ticks_msec();
while (is_processing()) {
_iterate();
uint64_t elapsed = (os.get_ticks_msec() - time_before);
- if (elapsed > 8) { // Process again after waiting 8 ticks
+ if (elapsed > 8) { // Process again after waiting 8 ticks.
break;
}
}
@@ -160,12 +160,12 @@ void FindInFiles::_process() {
void FindInFiles::_iterate() {
if (_folders_stack.size() != 0) {
- // Scan folders first so we can build a list of files and have progress info later
+ // Scan folders first so we can build a list of files and have progress info later.
PackedStringArray &folders_to_scan = _folders_stack.write[_folders_stack.size() - 1];
if (folders_to_scan.size() != 0) {
- // Scan one folder below
+ // Scan one folder below.
String folder_name = folders_to_scan[folders_to_scan.size() - 1];
pop_back(folders_to_scan);
@@ -178,19 +178,19 @@ void FindInFiles::_iterate() {
_folders_stack.push_back(sub_dirs);
} else {
- // Go back one level
+ // Go back one level.
pop_back(_folders_stack);
_current_dir = _current_dir.get_base_dir();
if (_folders_stack.size() == 0) {
- // All folders scanned
+ // All folders scanned.
_initial_files_count = _files_to_scan.size();
}
}
} else if (_files_to_scan.size() != 0) {
- // Then scan files
+ // Then scan files.
String fpath = _files_to_scan[_files_to_scan.size() - 1];
pop_back(_files_to_scan);
@@ -228,12 +228,12 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) {
break;
}
- // If there is a .gdignore file in the directory, don't bother searching it
+ // If there is a .gdignore file in the directory, skip searching the directory.
if (file == ".gdignore") {
break;
}
- // Ignore special dirs (such as .git and project data directory)
+ // Ignore special directories (such as those beginning with . and the project data directory).
String project_data_dir_name = ProjectSettings::get_singleton()->get_project_data_dir_name();
if (file.begins_with(".") || file == project_data_dir_name) {
continue;
@@ -264,7 +264,7 @@ void FindInFiles::_scan_file(String fpath) {
int line_number = 0;
while (!f->eof_reached()) {
- // line number starts at 1
+ // Line number starts at 1.
++line_number;
int begin = 0;
@@ -331,7 +331,7 @@ FindInFilesDialog::FindInFilesDialog() {
_replace_text_line_edit->hide();
gc->add_child(_replace_text_line_edit);
- gc->add_child(memnew(Control)); // Space to maintain the grid aligned.
+ gc->add_child(memnew(Control)); // Space to maintain the grid alignment.
{
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -421,7 +421,7 @@ void FindInFilesDialog::set_find_in_files_mode(FindInFilesMode p_mode) {
_replace_text_line_edit->show();
}
- // After hiding some child controls, let's recalculate proper Dialog size
+ // Recalculate the dialog size after hiding child controls.
set_size(Size2(get_size().x, 0));
}
@@ -448,7 +448,7 @@ String FindInFilesDialog::get_folder() const {
}
Set<String> FindInFilesDialog::get_filter() const {
- // could check the _filters_preferences but it might not have been generated yet.
+ // Could check the _filters_preferences but it might not have been generated yet.
Set<String> filters;
for (int i = 0; i < _filters_container->get_child_count(); ++i) {
CheckBox *cb = (CheckBox *)_filters_container->get_child(i);
@@ -492,6 +492,7 @@ void FindInFilesDialog::custom_action(const String &p_action) {
CheckBox *cb = (CheckBox *)_filters_container->get_child(i);
_filters_preferences[cb->get_text()] = cb->is_pressed();
}
+
if (p_action == "find") {
emit_signal(SNAME(SIGNAL_FIND_REQUESTED));
hide();
@@ -510,7 +511,7 @@ void FindInFilesDialog::_on_search_text_modified(String text) {
}
void FindInFilesDialog::_on_search_text_submitted(String text) {
- // This allows to trigger a global search without leaving the keyboard
+ // This allows to trigger a global search without leaving the keyboard.
if (!_find_button->is_disabled()) {
if (_mode == SEARCH_MODE) {
custom_action("find");
@@ -525,7 +526,7 @@ void FindInFilesDialog::_on_search_text_submitted(String text) {
}
void FindInFilesDialog::_on_replace_text_submitted(String text) {
- // This allows to trigger a global search without leaving the keyboard
+ // This allows to trigger a global search without leaving the keyboard.
if (!_replace_button->is_disabled()) {
if (_mode == REPLACE_MODE) {
custom_action("replace");
@@ -641,13 +642,12 @@ void FindInFilesPanel::set_with_replace(bool with_replace) {
_replace_container->set_visible(with_replace);
if (with_replace) {
- // Results show checkboxes on their left so they can be opted out
+ // Results show checkboxes on their left so they can be opted out.
_results_display->set_columns(2);
_results_display->set_column_expand(0, false);
_results_display->set_column_custom_minimum_width(0, 48 * EDSCALE);
-
} else {
- // Results are single-cell items
+ // Results are single-cell items.
_results_display->set_column_expand(0, true);
_results_display->set_columns(1);
}
@@ -708,12 +708,12 @@ void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin
file_item->set_text(0, fpath);
file_item->set_metadata(0, fpath);
- // The width of this column is restrained to checkboxes, but that doesn't make sense for the parent items,
- // so we override their width so they can expand to full width
+ // The width of this column is restrained to checkboxes,
+ // but that doesn't make sense for the parent items,
+ // so we override their width so they can expand to full width.
file_item->set_expand_right(0, true);
_file_items[fpath] = file_item;
-
} else {
file_item = E->value();
}
@@ -725,7 +725,7 @@ void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin
// Do this first because it resets properties of the cell...
item->set_cell_mode(text_index, TreeItem::CELL_MODE_CUSTOM);
- // Trim result item line
+ // Trim result item line.
int old_text_size = text.size();
text = text.strip_edges(true, false);
int chars_removed = old_text_size - text.size();
@@ -780,9 +780,8 @@ void FindInFilesPanel::_on_item_edited() {
if (item->is_checked(0)) {
item->set_custom_color(1, _results_display->get_theme_color(SNAME("font_color")));
-
} else {
- // Grey out
+ // Grey out.
Color color = _results_display->get_theme_color(SNAME("font_color"));
color.a /= 2.0;
item->set_custom_color(1, color);
@@ -857,19 +856,19 @@ void FindInFilesPanel::_on_replace_all_clicked() {
}
if (locations.size() != 0) {
- // Results are sorted by file, so we can batch replaces
+ // Results are sorted by file, so we can batch replaces.
apply_replaces_in_file(fpath, locations, replace_text);
modified_files.push_back(fpath);
}
}
- // Hide replace bar so we can't trigger the action twice without doing a new search
+ // Hide replace bar so we can't trigger the action twice without doing a new search.
_replace_container->hide();
emit_signal(SNAME(SIGNAL_FILES_MODIFIED), modified_files);
}
-// Same as get_line, but preserves line ending characters
+// Same as get_line, but preserves line ending characters.
class ConservativeGetLine {
public:
String get_line(FileAccess *f) {
@@ -941,7 +940,7 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result>
}
line = line.left(repl_begin) + new_text + line.substr(repl_end);
- // keep an offset in case there are successive replaces in the same line
+ // Keep an offset in case there are successive replaces in the same line.
offset += new_text.length() - (repl_end - repl_begin);
}
@@ -951,7 +950,7 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result>
buffer += conservative.get_line(f);
}
- // Now the modified contents are in the buffer, rewrite the file with our changes
+ // Now the modified contents are in the buffer, rewrite the file with our changes.
Error err = f->reopen(fpath, FileAccess::WRITE);
ERR_FAIL_COND_MSG(err != OK, "Cannot create file in path '" + fpath + "'.");
diff --git a/editor/icons/FogMaterial.svg b/editor/icons/FogMaterial.svg
new file mode 100644
index 0000000000..5db7dea374
--- /dev/null
+++ b/editor/icons/FogMaterial.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4.5 9.0000002c-.2761429-.0000014-.5000014.2238571-.5.5-.0000014.2761429.2238571.5000008.5.4999998l8-.0000002c.276143.0000012.500001-.2238569.5-.4999998.000001-.2761429-.223857-.5000014-.5-.5z" fill="#45d7ff"/><path d="m3.5 11c-.2761429-.000001-.5000014.223857-.5.5-.0000014.276143.2238571.500001.5.5h5c.2761429.000001.500001-.223857.5-.5.000001-.276143-.2238571-.500001-.5-.5z" fill="#8045ff"/><path d="m5.5 13c-.2761424 0-.5.223858-.5.5s.2238576.5.5.5h5c.276142 0 .5-.223858.5-.5s-.223858-.5-.5-.5z" fill="#ff4596"/><path d="m15 7h-13.936663c.2611574 1 1.436663 1 1.436663 1h11.5s1 0 1-1z" fill="#45ffa2"/><path d="m13.857422 5h-10.857422s-2 0-2 1.5c0 .216176.0100075.3416435.063337.5h13.936663c0-1-1.5-1-1.5-1s.23811-.4733054.357422-1z" fill="#80ff45"/><path d="m11.152344 3h1.847656c-.730134-.4197888-1.344054-.2676656-1.847656 0z" fill="#ff4545"/><path d="m9.7089844 3h-6.2714844c-.4375 1-.4375 2-.4375 2h10.857422c.149158-.6584498.108902-1.4444139-.857422-2h-1.847656c-.696054.3699541-1.152344 1-1.152344 1s-.161454-.5556722-.2910156-1z" fill="#ffe345"/><path d="m6.5 1c-1.75 0-2.625 1-3.0625 2h6.2714844c-.2591912-.8888889-.8754469-2-3.2089844-2z" fill="#ff4545"/><path d="m10.5 11c-.276143-.000001-.500001.223857-.5.5-.000001.276143.223857.500001.5.5h2.5c.276143.000001.500001-.223857.5-.5.000001-.276143-.223857-.500001-.5-.5z" fill="#8045ff"/></svg>
diff --git a/editor/icons/FogVolume.svg b/editor/icons/FogVolume.svg
new file mode 100644
index 0000000000..b0a18eb29d
--- /dev/null
+++ b/editor/icons/FogVolume.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><g fill-opacity=".996078"><path d="m4.5 9.0000002c-.2761429-.0000014-.5000014.2238571-.5.5-.0000014.2761429.2238571.5000008.5.4999998l8-.0000002c.276143.0000012.500001-.2238569.5-.4999998.000001-.2761429-.223857-.5000014-.5-.5z"/><path d="m3.5 11c-.2761429-.000001-.5000014.223857-.5.5-.0000014.276143.2238571.500001.5.5h5c.2761429.000001.500001-.223857.5-.5.000001-.276143-.2238571-.500001-.5-.5z"/><path d="m5.5 13c-.2761424 0-.5.223858-.5.5s.2238576.5.5.5h5c.276142 0 .5-.223858.5-.5s-.223858-.5-.5-.5z"/></g><path d="m2.5 8s-1.5 0-1.5-1.5 2-1.5 2-1.5 0-4 3.5-4 3.5 3 3.5 3 1.260711-2 3-1 .5 3 .5 3 1.5 0 1.5 1-1 1-1 1z" fill-opacity=".99608"/><path d="m10.5 11c-.276143-.000001-.500001.223857-.5.5-.000001.276143.223857.500001.5.5h2.5c.276143.000001.500001-.223857.5-.5.000001-.276143-.223857-.500001-.5-.5z" fill-opacity=".996078"/></g></svg>
diff --git a/editor/icons/GradientTexture2D.svg b/editor/icons/GradientTexture2D.svg
new file mode 100644
index 0000000000..ef40323b8c
--- /dev/null
+++ b/editor/icons/GradientTexture2D.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g fill="#e0e0e0"> <path d="M 2,1 C 1.447715,1 1,1.4477153 1,2 v 12.000001 c 0,0.552285 0.447715,1 1,1 h 11.999999 c 0.552285,0 1,-0.447715 1,-1 V 2 c 0,-0.5522847 -0.447715,-1 -1,-1 z m 1,2.0000001 h 9.999999 V 11.000001 H 3 Z" fill-opacity="0.99608"/> <path d="m 5.5,3.5 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 1,0 h 1 v 1 h -1 v 1 h 1 v 1 h 1 v 1 h 1 v -1 h 1 v 1 h 1 v -1 -1 -1 -1 -1 h -1 -1 -1 -1 -1 z m 4,4 h -1 v 1 h 1 z m 0,1 v 1 h 1 v -1 z m -1,0 h -1 v 1 h 1 z m -1,0 v -1 h -1 v 1 z m -1,-1 v -1 h -1 v 1 z m -1,0 h -1 v 1 h 1 z m 0,-1 v -1 h -1 v 1 z m -1,-1 v -1 h -1 v 1 z" /> </g> </svg>
diff --git a/editor/icons/OverbrightIndicator.svg b/editor/icons/OverbrightIndicator.svg
index 70894361ce..f618980d51 100644
--- a/editor/icons/OverbrightIndicator.svg
+++ b/editor/icons/OverbrightIndicator.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v10l10-10z" fill="#fff"/><path d="m0 12 12-12h-2l-10 10z" fill="#000003"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.5.5v10l10-10z" fill="#fff" stroke="#000"/><path d="m0 12 12-12h-1.714286l-10.285714 10.285714z" fill="#000003" stroke-width="2"/></svg>
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index 4cd9066350..19b4943e6d 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -541,7 +541,10 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
COLLADA_PRINT("node name: " + parser.get_node_name());
- if (!parser.is_empty() && (parser.get_node_name() == "profile_COMMON" || parser.get_node_name() == "technique" || parser.get_node_name() == "extra")) {
+ if (!parser.is_empty() &&
+ (parser.get_node_name() == "profile_COMMON" ||
+ parser.get_node_name() == "technique" ||
+ parser.get_node_name() == "extra")) {
_parse_effect_material(parser, effect, id); // try again
} else if (parser.get_node_name() == "newparam") {
@@ -551,9 +554,9 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
COLLADA_PRINT("param: " + name + " value:" + String(value));
} else if (parser.get_node_name() == "constant" ||
- parser.get_node_name() == "lambert" ||
- parser.get_node_name() == "phong" ||
- parser.get_node_name() == "blinn") {
+ parser.get_node_name() == "lambert" ||
+ parser.get_node_name() == "phong" ||
+ parser.get_node_name() == "blinn") {
COLLADA_PRINT("shade model: " + parser.get_node_name());
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
@@ -627,10 +630,11 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
} else if (what == "shininess") {
effect.shininess = _parse_param(parser);
}
- } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && (parser.get_node_name() == "constant" ||
- parser.get_node_name() == "lambert" ||
- parser.get_node_name() == "phong" ||
- parser.get_node_name() == "blinn")) {
+ } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END &&
+ (parser.get_node_name() == "constant" ||
+ parser.get_node_name() == "lambert" ||
+ parser.get_node_name() == "phong" ||
+ parser.get_node_name() == "blinn")) {
break;
}
}
@@ -681,10 +685,10 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
parser.skip_section();
}
} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END &&
- (parser.get_node_name() == "effect" ||
- parser.get_node_name() == "profile_COMMON" ||
- parser.get_node_name() == "technique" ||
- parser.get_node_name() == "extra")) {
+ (parser.get_node_name() == "effect" ||
+ parser.get_node_name() == "profile_COMMON" ||
+ parser.get_node_name() == "technique" ||
+ parser.get_node_name() == "extra")) {
break;
}
}
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index ac8adedf2f..f9aa550e7d 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -1650,8 +1650,7 @@ void ColladaImport::create_animation(int p_clip, bool p_import_value_tracks) {
Vector3 s = xform.basis.get_scale();
bool singular_matrix = Math::is_zero_approx(s.x) || Math::is_zero_approx(s.y) || Math::is_zero_approx(s.z);
- Quaternion q = singular_matrix ? Quaternion() :
- xform.basis.get_rotation_quaternion();
+ Quaternion q = singular_matrix ? Quaternion() : xform.basis.get_rotation_quaternion();
Vector3 l = xform.origin;
if (position_idx >= 0) {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index bebf05d481..7d3b945b04 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -342,6 +342,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
+ ERR_FAIL_NULL_MSG(mesh->get_mesh(), "Cannot generate shape list with null mesh value");
if (!p_convex) {
Ref<Shape3D> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
@@ -1299,27 +1300,28 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
if (p_option == "primitive/position" || p_option == "primitive/rotation") {
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
return generate_physics &&
- physics_shape >= SHAPE_TYPE_BOX;
+ physics_shape >= SHAPE_TYPE_BOX;
}
if (p_option == "primitive/size") {
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
return generate_physics &&
- physics_shape == SHAPE_TYPE_BOX;
+ physics_shape == SHAPE_TYPE_BOX;
}
if (p_option == "primitive/radius") {
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
- return generate_physics && (physics_shape == SHAPE_TYPE_SPHERE ||
- physics_shape == SHAPE_TYPE_CYLINDER ||
- physics_shape == SHAPE_TYPE_CAPSULE);
+ return generate_physics &&
+ (physics_shape == SHAPE_TYPE_SPHERE ||
+ physics_shape == SHAPE_TYPE_CYLINDER ||
+ physics_shape == SHAPE_TYPE_CAPSULE);
}
if (p_option == "primitive/height") {
const ShapeType physics_shape = (ShapeType)p_options["physics/shape_type"].operator int();
return generate_physics &&
- (physics_shape == SHAPE_TYPE_CYLINDER ||
- physics_shape == SHAPE_TYPE_CAPSULE);
+ (physics_shape == SHAPE_TYPE_CYLINDER ||
+ physics_shape == SHAPE_TYPE_CAPSULE);
}
} break;
case INTERNAL_IMPORT_CATEGORY_MESH: {
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index 2db1db9e51..89383d3dde 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -252,13 +252,13 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
//loop point info!
/**
- * Consider exploring next document:
- * http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf
- * Especially on page:
- * 16 - 17
- * Timestamp:
- * 22:38 06.07.2017 GMT
- **/
+ * Consider exploring next document:
+ * http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf
+ * Especially on page:
+ * 16 - 17
+ * Timestamp:
+ * 22:38 06.07.2017 GMT
+ **/
for (int i = 0; i < 10; i++) {
file->get_32(); // i wish to know why should i do this... no doc!
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 5544d9261e..0e1bdf0155 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -2983,18 +2983,16 @@ void CanvasItemEditor::_draw_ruler_tool() {
const Vector2 end_to_begin = (end - begin);
- real_t arc_1_start_angle =
- end_to_begin.x < 0 ?
- (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0) :
- (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
+ real_t arc_1_start_angle = end_to_begin.x < 0
+ ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0)
+ : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
// Constrain arc to triangle height & max size
real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
- real_t arc_2_start_angle =
- end_to_begin.x < 0 ?
- (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad) :
- (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
+ real_t arc_2_start_angle = end_to_begin.x < 0
+ ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad)
+ : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
// Constrain arc to triangle width & max size
real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 4a22dc5b62..43eb6a7ce9 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -354,9 +354,9 @@ void CurveEditor::open_context_menu(Vector2 pos) {
_context_menu->add_check_item(TTR("Linear"), CONTEXT_LINEAR);
- bool is_linear = _selected_tangent == TANGENT_LEFT ?
- _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR :
- _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR;
+ bool is_linear = _selected_tangent == TANGENT_LEFT
+ ? _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR
+ : _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR;
_context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_LINEAR), is_linear);
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index 1512e1817a..cc916aad8b 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -34,6 +34,7 @@
#include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/editor_debugger_server.h"
#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
#include "editor/fileserver/editor_file_server.h"
#include "scene/gui/menu_button.h"
@@ -52,6 +53,8 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d
EditorDebuggerNode *debugger = memnew(EditorDebuggerNode);
Button *db = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Debugger"), debugger);
+ // Add separation for the warning/error icon that is displayed later.
+ db->add_theme_constant_override("hseparation", 6 * EDSCALE);
debugger->set_tool_button(db);
// Main editor debug menu.
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
deleted file mode 100644
index 16cafda899..0000000000
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ /dev/null
@@ -1,410 +0,0 @@
-/*************************************************************************/
-/* item_list_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "item_list_editor_plugin.h"
-
-#include "core/io/resource_loader.h"
-#include "editor/editor_scale.h"
-
-bool ItemListPlugin::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- int idx = name.get_slice("/", 0).to_int();
- String what = name.get_slice("/", 1);
-
- if (what == "text") {
- set_item_text(idx, p_value);
- } else if (what == "icon") {
- set_item_icon(idx, p_value);
- } else if (what == "checkable") {
- // This keeps compatibility to/from versions where this property was a boolean, before radio buttons
- switch ((int)p_value) {
- case 0:
- case 1:
- set_item_checkable(idx, p_value);
- break;
- case 2:
- set_item_radio_checkable(idx, true);
- break;
- }
- } else if (what == "checked") {
- set_item_checked(idx, p_value);
- } else if (what == "id") {
- set_item_id(idx, p_value);
- } else if (what == "enabled") {
- set_item_enabled(idx, p_value);
- } else if (what == "separator") {
- set_item_separator(idx, p_value);
- } else {
- return false;
- }
-
- return true;
-}
-
-bool ItemListPlugin::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- int idx = name.get_slice("/", 0).to_int();
- String what = name.get_slice("/", 1);
-
- if (what == "text") {
- r_ret = get_item_text(idx);
- } else if (what == "icon") {
- r_ret = get_item_icon(idx);
- } else if (what == "checkable") {
- // This keeps compatibility to/from versions where this property was a boolean, before radio buttons
- if (!is_item_checkable(idx)) {
- r_ret = 0;
- } else {
- r_ret = is_item_radio_checkable(idx) ? 2 : 1;
- }
- } else if (what == "checked") {
- r_ret = is_item_checked(idx);
- } else if (what == "id") {
- r_ret = get_item_id(idx);
- } else if (what == "enabled") {
- r_ret = is_item_enabled(idx);
- } else if (what == "separator") {
- r_ret = is_item_separator(idx);
- } else {
- return false;
- }
-
- return true;
-}
-
-void ItemListPlugin::_get_property_list(List<PropertyInfo> *p_list) const {
- for (int i = 0; i < get_item_count(); i++) {
- String base = itos(i) + "/";
-
- p_list->push_back(PropertyInfo(Variant::STRING, base + "text"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, base + "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
-
- int flags = get_flags();
-
- if (flags & FLAG_CHECKABLE) {
- p_list->push_back(PropertyInfo(Variant::INT, base + "checkable", PROPERTY_HINT_ENUM, "No,As checkbox,As radio button"));
- p_list->push_back(PropertyInfo(Variant::BOOL, base + "checked"));
- }
-
- if (flags & FLAG_ID) {
- p_list->push_back(PropertyInfo(Variant::INT, base + "id", PROPERTY_HINT_RANGE, "-1,4096"));
- }
-
- if (flags & FLAG_ENABLE) {
- p_list->push_back(PropertyInfo(Variant::BOOL, base + "enabled"));
- }
-
- if (flags & FLAG_SEPARATOR) {
- p_list->push_back(PropertyInfo(Variant::BOOL, base + "separator"));
- }
- }
-}
-
-///////////////////////////////////////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////////////////////////////////////////////
-
-void ItemListOptionButtonPlugin::set_object(Object *p_object) {
- ob = Object::cast_to<OptionButton>(p_object);
-}
-
-bool ItemListOptionButtonPlugin::handles(Object *p_object) const {
- return p_object->is_class("OptionButton");
-}
-
-int ItemListOptionButtonPlugin::get_flags() const {
- return FLAG_ICON | FLAG_ID | FLAG_ENABLE;
-}
-
-void ItemListOptionButtonPlugin::add_item() {
- ob->add_item(vformat(TTR("Item %d"), ob->get_item_count()));
- notify_property_list_changed();
-}
-
-int ItemListOptionButtonPlugin::get_item_count() const {
- return ob->get_item_count();
-}
-
-void ItemListOptionButtonPlugin::erase(int p_idx) {
- ob->remove_item(p_idx);
- notify_property_list_changed();
-}
-
-ItemListOptionButtonPlugin::ItemListOptionButtonPlugin() {
- ob = nullptr;
-}
-
-///////////////////////////////////////////////////////////////
-
-void ItemListPopupMenuPlugin::set_object(Object *p_object) {
- if (p_object->is_class("MenuButton")) {
- pp = Object::cast_to<MenuButton>(p_object)->get_popup();
- } else {
- pp = Object::cast_to<PopupMenu>(p_object);
- }
-}
-
-bool ItemListPopupMenuPlugin::handles(Object *p_object) const {
- return p_object->is_class("PopupMenu") || p_object->is_class("MenuButton");
-}
-
-int ItemListPopupMenuPlugin::get_flags() const {
- return FLAG_ICON | FLAG_CHECKABLE | FLAG_ID | FLAG_ENABLE | FLAG_SEPARATOR;
-}
-
-void ItemListPopupMenuPlugin::add_item() {
- pp->add_item(vformat(TTR("Item %d"), pp->get_item_count()));
- notify_property_list_changed();
-}
-
-int ItemListPopupMenuPlugin::get_item_count() const {
- return pp->get_item_count();
-}
-
-void ItemListPopupMenuPlugin::erase(int p_idx) {
- pp->remove_item(p_idx);
- notify_property_list_changed();
-}
-
-ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() {
- pp = nullptr;
-}
-
-///////////////////////////////////////////////////////////////
-
-void ItemListItemListPlugin::set_object(Object *p_object) {
- pp = Object::cast_to<ItemList>(p_object);
-}
-
-bool ItemListItemListPlugin::handles(Object *p_object) const {
- return p_object->is_class("ItemList");
-}
-
-int ItemListItemListPlugin::get_flags() const {
- return FLAG_ICON | FLAG_ENABLE;
-}
-
-void ItemListItemListPlugin::add_item() {
- pp->add_item(vformat(TTR("Item %d"), pp->get_item_count()));
- notify_property_list_changed();
-}
-
-int ItemListItemListPlugin::get_item_count() const {
- return pp->get_item_count();
-}
-
-void ItemListItemListPlugin::erase(int p_idx) {
- pp->remove_item(p_idx);
- notify_property_list_changed();
-}
-
-ItemListItemListPlugin::ItemListItemListPlugin() {
- pp = nullptr;
-}
-
-///////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////
-
-void ItemListEditor::_node_removed(Node *p_node) {
- if (p_node == item_list) {
- item_list = nullptr;
- hide();
- dialog->hide();
- }
-}
-
-void ItemListEditor::_notification(int p_notification) {
- if (p_notification == NOTIFICATION_ENTER_TREE || p_notification == NOTIFICATION_THEME_CHANGED) {
- add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
- clear_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- del_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- } else if (p_notification == NOTIFICATION_READY) {
- get_tree()->connect("node_removed", callable_mp(this, &ItemListEditor::_node_removed));
- }
-}
-
-void ItemListEditor::_add_pressed() {
- if (selected_idx == -1) {
- return;
- }
-
- item_plugins[selected_idx]->add_item();
-}
-
-void ItemListEditor::_clear_pressed() {
- for (int i = item_plugins[selected_idx]->get_item_count() - 1; i >= 0; i--) {
- item_plugins[selected_idx]->erase(i);
- }
-}
-
-void ItemListEditor::_delete_pressed() {
- if (selected_idx == -1) {
- return;
- }
-
- String current_selected = (String)property_editor->get_selected_path();
-
- if (current_selected == "") {
- return;
- }
-
- // FIXME: Currently relying on selecting a *property* to derive what item to delete
- // e.g. you select "1/enabled" to delete item 1.
- // This should be fixed so that you can delete by selecting the item section header,
- // or a delete button on that header.
-
- int idx = current_selected.get_slice("/", 0).to_int();
-
- item_plugins[selected_idx]->erase(idx);
-}
-
-void ItemListEditor::_edit_items() {
- dialog->popup_centered_clamped(Vector2(425, 1200) * EDSCALE, 0.8);
-}
-
-void ItemListEditor::edit(Node *p_item_list) {
- item_list = p_item_list;
-
- if (!item_list) {
- selected_idx = -1;
- property_editor->edit(nullptr);
- return;
- }
-
- for (int i = 0; i < item_plugins.size(); i++) {
- if (item_plugins[i]->handles(p_item_list)) {
- item_plugins[i]->set_object(p_item_list);
- property_editor->edit(item_plugins[i]);
-
- toolbar_button->set_icon(EditorNode::get_singleton()->get_object_icon(item_list, ""));
-
- selected_idx = i;
- return;
- }
- }
-
- selected_idx = -1;
- property_editor->edit(nullptr);
-}
-
-bool ItemListEditor::handles(Object *p_object) const {
- for (int i = 0; i < item_plugins.size(); i++) {
- if (item_plugins[i]->handles(p_object)) {
- return true;
- }
- }
-
- return false;
-}
-
-void ItemListEditor::_bind_methods() {
-}
-
-ItemListEditor::ItemListEditor() {
- selected_idx = -1;
- item_list = nullptr;
-
- toolbar_button = memnew(Button);
- toolbar_button->set_flat(true);
- toolbar_button->set_text(TTR("Items"));
- add_child(toolbar_button);
- toolbar_button->connect("pressed", callable_mp(this, &ItemListEditor::_edit_items));
-
- dialog = memnew(AcceptDialog);
- dialog->set_title(TTR("Item List Editor"));
- add_child(dialog);
-
- VBoxContainer *vbc = memnew(VBoxContainer);
- dialog->add_child(vbc);
- //dialog->set_child_rect(vbc);
-
- HBoxContainer *hbc = memnew(HBoxContainer);
- hbc->set_h_size_flags(SIZE_EXPAND_FILL);
- vbc->add_child(hbc);
-
- add_button = memnew(Button);
- add_button->set_text(TTR("Add"));
- hbc->add_child(add_button);
- add_button->connect("pressed", callable_mp(this, &ItemListEditor::_add_pressed));
-
- hbc->add_spacer();
-
- clear_button = memnew(Button);
- clear_button->set_text(TTR("Delete All"));
- hbc->add_child(clear_button);
- clear_button->connect("pressed", callable_mp(this, &ItemListEditor::_clear_pressed));
-
- del_button = memnew(Button);
- del_button->set_text(TTR("Delete"));
- hbc->add_child(del_button);
- del_button->connect("pressed", callable_mp(this, &ItemListEditor::_delete_pressed));
-
- property_editor = memnew(EditorInspector);
- vbc->add_child(property_editor);
- property_editor->set_v_size_flags(SIZE_EXPAND_FILL);
-}
-
-ItemListEditor::~ItemListEditor() {
- for (int i = 0; i < item_plugins.size(); i++) {
- memdelete(item_plugins[i]);
- }
-}
-
-void ItemListEditorPlugin::edit(Object *p_object) {
- item_list_editor->edit(Object::cast_to<Node>(p_object));
-}
-
-bool ItemListEditorPlugin::handles(Object *p_object) const {
- return item_list_editor->handles(p_object);
-}
-
-void ItemListEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- item_list_editor->show();
- } else {
- item_list_editor->hide();
- item_list_editor->edit(nullptr);
- }
-}
-
-ItemListEditorPlugin::ItemListEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- item_list_editor = memnew(ItemListEditor);
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(item_list_editor);
-
- item_list_editor->hide();
- item_list_editor->add_plugin(memnew(ItemListOptionButtonPlugin));
- item_list_editor->add_plugin(memnew(ItemListPopupMenuPlugin));
- item_list_editor->add_plugin(memnew(ItemListItemListPlugin));
-}
-
-ItemListEditorPlugin::~ItemListEditorPlugin() {
-}
diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h
deleted file mode 100644
index 8f61aef083..0000000000
--- a/editor/plugins/item_list_editor_plugin.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*************************************************************************/
-/* item_list_editor_plugin.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 ITEM_LIST_EDITOR_PLUGIN_H
-#define ITEM_LIST_EDITOR_PLUGIN_H
-
-#include "canvas_item_editor_plugin.h"
-#include "editor/editor_inspector.h"
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
-#include "scene/gui/menu_button.h"
-#include "scene/gui/option_button.h"
-#include "scene/gui/popup_menu.h"
-
-class ItemListPlugin : public Object {
- GDCLASS(ItemListPlugin, Object);
-
-protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- enum Flags {
- FLAG_ICON = 1,
- FLAG_CHECKABLE = 2,
- FLAG_ID = 4,
- FLAG_ENABLE = 8,
- FLAG_SEPARATOR = 16
- };
-
- virtual void set_object(Object *p_object) = 0;
- virtual bool handles(Object *p_object) const = 0;
-
- virtual int get_flags() const = 0;
-
- virtual void set_item_text(int p_idx, const String &p_text) {}
- virtual String get_item_text(int p_idx) const { return ""; };
-
- virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) {}
- virtual Ref<Texture2D> get_item_icon(int p_idx) const { return Ref<Texture2D>(); };
-
- virtual void set_item_checkable(int p_idx, bool p_check) {}
- virtual void set_item_radio_checkable(int p_idx, bool p_check) {}
- virtual bool is_item_checkable(int p_idx) const { return false; };
- virtual bool is_item_radio_checkable(int p_idx) const { return false; };
-
- virtual void set_item_checked(int p_idx, bool p_checked) {}
- virtual bool is_item_checked(int p_idx) const { return false; };
-
- virtual void set_item_enabled(int p_idx, int p_enabled) {}
- virtual bool is_item_enabled(int p_idx) const { return false; };
-
- virtual void set_item_id(int p_idx, int p_id) {}
- virtual int get_item_id(int p_idx) const { return -1; };
-
- virtual void set_item_separator(int p_idx, bool p_separator) {}
- virtual bool is_item_separator(int p_idx) const { return false; };
-
- virtual void add_item() = 0;
- virtual int get_item_count() const = 0;
- virtual void erase(int p_idx) = 0;
-
- ItemListPlugin() {}
-};
-
-///////////////////////////////////////////////////////////////
-
-class ItemListOptionButtonPlugin : public ItemListPlugin {
- GDCLASS(ItemListOptionButtonPlugin, ItemListPlugin);
-
- OptionButton *ob;
-
-public:
- virtual void set_object(Object *p_object) override;
- virtual bool handles(Object *p_object) const override;
- virtual int get_flags() const override;
-
- virtual void set_item_text(int p_idx, const String &p_text) override { ob->set_item_text(p_idx, p_text); }
- virtual String get_item_text(int p_idx) const override { return ob->get_item_text(p_idx); }
-
- virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) override { ob->set_item_icon(p_idx, p_tex); }
- virtual Ref<Texture2D> get_item_icon(int p_idx) const override { return ob->get_item_icon(p_idx); }
-
- virtual void set_item_enabled(int p_idx, int p_enabled) override { ob->set_item_disabled(p_idx, !p_enabled); }
- virtual bool is_item_enabled(int p_idx) const override { return !ob->is_item_disabled(p_idx); }
-
- virtual void set_item_id(int p_idx, int p_id) override { ob->set_item_id(p_idx, p_id); }
- virtual int get_item_id(int p_idx) const override { return ob->get_item_id(p_idx); }
-
- virtual void add_item() override;
- virtual int get_item_count() const override;
- virtual void erase(int p_idx) override;
-
- ItemListOptionButtonPlugin();
-};
-
-class ItemListPopupMenuPlugin : public ItemListPlugin {
- GDCLASS(ItemListPopupMenuPlugin, ItemListPlugin);
-
- PopupMenu *pp;
-
-public:
- virtual void set_object(Object *p_object) override;
- virtual bool handles(Object *p_object) const override;
- virtual int get_flags() const override;
-
- virtual void set_item_text(int p_idx, const String &p_text) override { pp->set_item_text(p_idx, p_text); }
- virtual String get_item_text(int p_idx) const override { return pp->get_item_text(p_idx); }
-
- virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) override { pp->set_item_icon(p_idx, p_tex); }
- virtual Ref<Texture2D> get_item_icon(int p_idx) const override { return pp->get_item_icon(p_idx); }
-
- virtual void set_item_checkable(int p_idx, bool p_check) override { pp->set_item_as_checkable(p_idx, p_check); }
- virtual void set_item_radio_checkable(int p_idx, bool p_check) override { pp->set_item_as_radio_checkable(p_idx, p_check); }
- virtual bool is_item_checkable(int p_idx) const override { return pp->is_item_checkable(p_idx); }
- virtual bool is_item_radio_checkable(int p_idx) const override { return pp->is_item_radio_checkable(p_idx); }
-
- virtual void set_item_checked(int p_idx, bool p_checked) override { pp->set_item_checked(p_idx, p_checked); }
- virtual bool is_item_checked(int p_idx) const override { return pp->is_item_checked(p_idx); }
-
- virtual void set_item_enabled(int p_idx, int p_enabled) override { pp->set_item_disabled(p_idx, !p_enabled); }
- virtual bool is_item_enabled(int p_idx) const override { return !pp->is_item_disabled(p_idx); }
-
- virtual void set_item_id(int p_idx, int p_id) override { pp->set_item_id(p_idx, p_id); }
- virtual int get_item_id(int p_idx) const override { return pp->get_item_id(p_idx); }
-
- virtual void set_item_separator(int p_idx, bool p_separator) override { pp->set_item_as_separator(p_idx, p_separator); }
- virtual bool is_item_separator(int p_idx) const override { return pp->is_item_separator(p_idx); }
-
- virtual void add_item() override;
- virtual int get_item_count() const override;
- virtual void erase(int p_idx) override;
-
- ItemListPopupMenuPlugin();
-};
-
-///////////////////////////////////////////////////////////////
-
-class ItemListItemListPlugin : public ItemListPlugin {
- GDCLASS(ItemListItemListPlugin, ItemListPlugin);
-
- ItemList *pp;
-
-public:
- virtual void set_object(Object *p_object) override;
- virtual bool handles(Object *p_object) const override;
- virtual int get_flags() const override;
-
- virtual void set_item_text(int p_idx, const String &p_text) override { pp->set_item_text(p_idx, p_text); }
- virtual String get_item_text(int p_idx) const override { return pp->get_item_text(p_idx); }
-
- virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) override { pp->set_item_icon(p_idx, p_tex); }
- virtual Ref<Texture2D> get_item_icon(int p_idx) const override { return pp->get_item_icon(p_idx); }
-
- virtual void set_item_enabled(int p_idx, int p_enabled) override { pp->set_item_disabled(p_idx, !p_enabled); }
- virtual bool is_item_enabled(int p_idx) const override { return !pp->is_item_disabled(p_idx); }
-
- virtual void add_item() override;
- virtual int get_item_count() const override;
- virtual void erase(int p_idx) override;
-
- ItemListItemListPlugin();
-};
-
-///////////////////////////////////////////////////////////////
-
-class ItemListEditor : public HBoxContainer {
- GDCLASS(ItemListEditor, HBoxContainer);
-
- Node *item_list;
-
- Button *toolbar_button;
-
- AcceptDialog *dialog;
- EditorInspector *property_editor;
- Tree *tree;
- Button *add_button;
- Button *del_button;
- Button *clear_button;
-
- int selected_idx;
-
- Vector<ItemListPlugin *> item_plugins;
-
- void _edit_items();
-
- void _add_pressed();
- void _delete_pressed();
- void _clear_pressed();
-
- void _node_removed(Node *p_node);
-
-protected:
- void _notification(int p_notification);
- static void _bind_methods();
-
-public:
- void edit(Node *p_item_list);
- bool handles(Object *p_object) const;
- void add_plugin(ItemListPlugin *p_plugin) { item_plugins.push_back(p_plugin); }
- ItemListEditor();
- ~ItemListEditor();
-};
-
-class ItemListEditorPlugin : public EditorPlugin {
- GDCLASS(ItemListEditorPlugin, EditorPlugin);
-
- ItemListEditor *item_list_editor;
- EditorNode *editor;
-
-public:
- virtual String get_name() const override { return "ItemList"; }
- bool has_main_screen() const override { return false; }
- virtual void edit(Object *p_object) override;
- virtual bool handles(Object *p_object) const override;
- virtual void make_visible(bool p_visible) override;
-
- ItemListEditorPlugin(EditorNode *p_node);
- ~ItemListEditorPlugin();
-};
-
-#endif // ITEM_LIST_EDITOR_PLUGIN_H
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 30945826bb..140d2952dd 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_scale.h"
#include "scene/gui/subviewport_container.h"
+#include "scene/resources/fog_material.h"
#include "scene/resources/particles_material.h"
#include "scene/resources/sky_material.h"
@@ -283,6 +284,52 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
return smat;
}
+String ORMMaterial3DConversionPlugin::converts_to() const {
+ return "ShaderMaterial";
+}
+
+bool ORMMaterial3DConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+ Ref<ORMMaterial3D> mat = p_resource;
+ return mat.is_valid();
+}
+
+Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_resource) const {
+ Ref<ORMMaterial3D> mat = p_resource;
+ ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
+
+ Ref<ShaderMaterial> smat;
+ smat.instantiate();
+
+ Ref<Shader> shader;
+ shader.instantiate();
+
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
+
+ shader->set_code(code);
+
+ smat->set_shader(shader);
+
+ List<PropertyInfo> params;
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+
+ for (const PropertyInfo &E : params) {
+ // Texture parameter has to be treated specially since ORMMaterial3D saved it
+ // as RID but ShaderMaterial needs Texture itself
+ Ref<Texture2D> texture = mat->get_texture_by_name(E.name);
+ if (texture.is_valid()) {
+ smat->set_shader_param(E.name, texture);
+ } else {
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
+ smat->set_shader_param(E.name, value);
+ }
+ }
+
+ smat->set_render_priority(mat->get_render_priority());
+ smat->set_local_to_scene(mat->is_local_to_scene());
+ smat->set_name(mat->get_name());
+ return smat;
+}
+
String ParticlesMaterialConversionPlugin::converts_to() const {
return "ShaderMaterial";
}
@@ -477,3 +524,40 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_name(mat->get_name());
return smat;
}
+
+String FogMaterialConversionPlugin::converts_to() const {
+ return "ShaderMaterial";
+}
+
+bool FogMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+ Ref<FogMaterial> mat = p_resource;
+ return mat.is_valid();
+}
+
+Ref<Resource> FogMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
+ Ref<FogMaterial> mat = p_resource;
+ ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
+
+ Ref<ShaderMaterial> smat;
+ smat.instantiate();
+
+ Ref<Shader> shader;
+ shader.instantiate();
+
+ String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid());
+
+ shader->set_code(code);
+
+ smat->set_shader(shader);
+
+ List<PropertyInfo> params;
+ RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+
+ for (const PropertyInfo &E : params) {
+ Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
+ smat->set_shader_param(E.name, value);
+ }
+
+ smat->set_render_priority(mat->get_render_priority());
+ return smat;
+}
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index a4532b58b3..62549843f7 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -107,6 +107,15 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};
+class ORMMaterial3DConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(ORMMaterial3DConversionPlugin, EditorResourceConversionPlugin);
+
+public:
+ virtual String converts_to() const override;
+ virtual bool handles(const Ref<Resource> &p_resource) const override;
+ virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
+};
+
class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin {
GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin);
@@ -152,4 +161,13 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};
+class FogMaterialConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(FogMaterialConversionPlugin, EditorResourceConversionPlugin);
+
+public:
+ virtual String converts_to() const override;
+ virtual bool handles(const Ref<Resource> &p_resource) const override;
+ virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
+};
+
#endif // MATERIAL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index b28f3e134c..74fbef3caf 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -41,6 +41,7 @@
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/cpu_particles_3d.h"
#include "scene/3d/decal.h"
+#include "scene/3d/fog_volume.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/3d/gpu_particles_collision_3d.h"
#include "scene/3d/joint_3d.h"
@@ -3641,15 +3642,15 @@ void LightmapGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
const float c4 = 0.886227;
const float c5 = 0.247708;
Vector3 light = (c1 * sh_col[8] * (n.x * n.x - n.y * n.y) +
- c3 * sh_col[6] * n.z * n.z +
- c4 * sh_col[0] -
- c5 * sh_col[6] +
- 2.0 * c1 * sh_col[4] * n.x * n.y +
- 2.0 * c1 * sh_col[7] * n.x * n.z +
- 2.0 * c1 * sh_col[5] * n.y * n.z +
- 2.0 * c2 * sh_col[3] * n.x +
- 2.0 * c2 * sh_col[1] * n.y +
- 2.0 * c2 * sh_col[2] * n.z);
+ c3 * sh_col[6] * n.z * n.z +
+ c4 * sh_col[0] -
+ c5 * sh_col[6] +
+ 2.0 * c1 * sh_col[4] * n.x * n.y +
+ 2.0 * c1 * sh_col[7] * n.x * n.z +
+ 2.0 * c1 * sh_col[5] * n.y * n.z +
+ 2.0 * c2 * sh_col[3] * n.x +
+ 2.0 * c2 * sh_col[1] * n.y +
+ 2.0 * c2 * sh_col[2] * n.z);
colors.push_back(Color(light.x, light.y, light.z, 1));
}
@@ -5272,3 +5273,119 @@ void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo(
#undef ADD_VTX
}
+
+////
+
+FogVolumeGizmoPlugin::FogVolumeGizmoPlugin() {
+ Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1));
+ create_material("shape_material", gizmo_color);
+ gizmo_color.a = 0.15;
+ create_material("shape_material_internal", gizmo_color);
+
+ create_handle_material("handles");
+}
+
+bool FogVolumeGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return (Object::cast_to<FogVolume>(p_spatial) != nullptr);
+}
+
+String FogVolumeGizmoPlugin::get_gizmo_name() const {
+ return "FogVolume";
+}
+
+int FogVolumeGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+ return "Extents";
+}
+
+Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+ return Vector3(p_gizmo->get_spatial_node()->call("get_extents"));
+}
+
+void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
+ Node3D *sn = p_gizmo->get_spatial_node();
+
+ Transform3D gt = sn->get_global_transform();
+ Transform3D gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+
+ Vector3 axis;
+ axis[p_id] = 1.0;
+ Vector3 ra, rb;
+ Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
+ float d = ra[p_id];
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (d < 0.001) {
+ d = 0.001;
+ }
+
+ Vector3 he = sn->call("get_extents");
+ he[p_id] = d;
+ sn->call("set_extents", he);
+}
+
+void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+ Node3D *sn = p_gizmo->get_spatial_node();
+
+ if (p_cancel) {
+ sn->call("set_extents", p_restore);
+ return;
+ }
+
+ UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Change Fog Volume Extents"));
+ ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
+ ur->add_undo_method(sn, "set_extents", p_restore);
+ ur->commit_action();
+}
+
+void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ Node3D *cs = p_gizmo->get_spatial_node();
+
+ p_gizmo->clear();
+
+ if (RS::FogVolumeShape(int(p_gizmo->get_spatial_node()->call("get_shape"))) != RS::FOG_VOLUME_SHAPE_WORLD) {
+ const Ref<Material> material =
+ get_material("shape_material", p_gizmo);
+ const Ref<Material> material_internal =
+ get_material("shape_material_internal", p_gizmo);
+
+ Ref<Material> handles_material = get_material("handles");
+
+ Vector<Vector3> lines;
+ AABB aabb;
+ aabb.position = -cs->call("get_extents").operator Vector3();
+ aabb.size = aabb.position * -2;
+
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+ for (int i = 0; i < 3; i++) {
+ Vector3 ax;
+ ax[i] = cs->call("get_extents").operator Vector3()[i];
+ handles.push_back(ax);
+ }
+
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
+ p_gizmo->add_handles(handles, handles_material);
+ }
+}
+
+/////
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index d1aca4d92e..56e4ad5518 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -669,4 +669,21 @@ public:
Joint3DGizmoPlugin();
};
+class FogVolumeGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(FogVolumeGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ int get_priority() const override;
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
+ Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
+ void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
+ void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
+
+ FogVolumeGizmoPlugin();
+};
+
#endif // NODE_3D_EDITOR_GIZMOS_H
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 632207befc..b99ccc1012 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1855,7 +1855,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
motion_snapped.snap(Vector3(snap, snap, snap));
// This might not be necessary anymore after issue #288 is solved (in 4.0?).
set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
List<Node *> &selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
@@ -1954,7 +1954,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 motion_snapped = motion;
motion_snapped.snap(Vector3(snap, snap, snap));
set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
- String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
+ String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
List<Node *> &selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
@@ -4376,7 +4376,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
const int wireframe_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME);
const int overdraw_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW);
const int shadeless_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS);
- const String unsupported_tooltip = TTR("Not available when using the GLES2 renderer.");
+ const String unsupported_tooltip = TTR("Not available when using the OpenGL renderer.");
view_menu->get_popup()->set_item_disabled(normal_idx, true);
view_menu->get_popup()->set_item_tooltip(normal_idx, unsupported_tooltip);
@@ -7004,6 +7004,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
add_gizmo_plugin(Ref<Joint3DGizmoPlugin>(memnew(Joint3DGizmoPlugin)));
add_gizmo_plugin(Ref<PhysicalBone3DGizmoPlugin>(memnew(PhysicalBone3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<FogVolumeGizmoPlugin>(memnew(FogVolumeGizmoPlugin)));
}
void Node3DEditor::_bind_methods() {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index e1318f52a8..8d647808ba 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -41,6 +41,7 @@
#include "scene/3d/world_environment.h"
#include "scene/gui/panel_container.h"
#include "scene/resources/environment.h"
+#include "scene/resources/fog_material.h"
#include "scene/resources/sky_material.h"
class Node3DEditor;
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index e2902feba1..f9a5f429d2 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -614,15 +614,6 @@ Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) {
menu->connect("id_pressed", callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed));
curve_edit->set_pressed(true);
- /*
- collision_polygon_editor = memnew( PathEditor(p_node) );
- editor->get_main_control()->add_child(collision_polygon_editor);
- collision_polygon_editor->set_margin(MARGIN_LEFT,200);
- collision_polygon_editor->set_margin(MARGIN_RIGHT,230);
- collision_polygon_editor->set_margin(MARGIN_TOP,0);
- collision_polygon_editor->set_margin(MARGIN_BOTTOM,10);
- collision_polygon_editor->hide();
- */
}
Path3DEditorPlugin::~Path3DEditorPlugin() {
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 677a5f1f2c..3f98560a2f 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -315,10 +315,7 @@ void ScriptEditorQuickOpen::_text_changed(const String &p_newtext) {
void ScriptEditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
Ref<InputEventKey> k = p_ie;
- if (k.is_valid() && (k->get_keycode() == KEY_UP ||
- k->get_keycode() == KEY_DOWN ||
- k->get_keycode() == KEY_PAGEUP ||
- k->get_keycode() == KEY_PAGEDOWN)) {
+ if (k.is_valid() && (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_PAGEUP || k->get_keycode() == KEY_PAGEDOWN)) {
search_options->gui_input(k);
search_box->accept_event();
}
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 2c02389db2..219498b5e7 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1396,11 +1396,12 @@ Variant ScriptTextEditor::get_drag_data_fw(const Point2 &p_point, Control *p_fro
bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
Dictionary d = p_data;
- if (d.has("type") && (String(d["type"]) == "resource" ||
- String(d["type"]) == "files" ||
- String(d["type"]) == "nodes" ||
- String(d["type"]) == "obj_property" ||
- String(d["type"]) == "files_and_dirs")) {
+ if (d.has("type") &&
+ (String(d["type"]) == "resource" ||
+ String(d["type"]) == "files" ||
+ String(d["type"]) == "nodes" ||
+ String(d["type"]) == "obj_property" ||
+ String(d["type"]) == "files_and_dirs")) {
return true;
}
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index a88e24c0d0..2731582288 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -178,6 +178,10 @@ void ShaderTextEditor::_check_shader_mode() {
mode = Shader::MODE_CANVAS_ITEM;
} else if (type == "particles") {
mode = Shader::MODE_PARTICLES;
+ } else if (type == "sky") {
+ mode = Shader::MODE_SKY;
+ } else if (type == "fog") {
+ mode = Shader::MODE_FOG;
} else {
mode = Shader::MODE_SPATIAL;
}
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 21ef94b999..39fbd86f77 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -99,7 +99,7 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
picker_button->show();
erase_button->show();
tools_settings_vsep_2->show();
- bucket_continuous_checkbox->show();
+ bucket_contiguous_checkbox->show();
random_tile_checkbox->show();
scatter_label->show();
scatter_spinbox->show();
@@ -543,9 +543,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
switch (drag_type) {
case DRAG_TYPE_PAINT: {
- Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_last_mouse_pos, mpos);
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_last_mouse_pos, mpos, drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -560,9 +560,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
- Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_continuous_checkbox->is_pressed());
+ Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -592,11 +592,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (mb->get_button_index() == MOUSE_BUTTON_LEFT || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (mb->is_pressed()) {
- if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- rmb_erasing = true;
+ // Pressed
+ if (erase_button->is_pressed() || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ drag_erasing = true;
}
- // Pressed
if (drag_type == DRAG_TYPE_CLIPBOARD_PASTE) {
// Do nothing.
} else if (tool_buttons_group->get_pressed_button() == select_tool_button) {
@@ -626,9 +626,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
drag_type = DRAG_TYPE_PAINT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, mpos, mpos);
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, mpos, mpos, drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -653,9 +653,9 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
for (int i = 0; i < line.size(); i++) {
if (!drag_modified.has(line[i])) {
- Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_continuous_checkbox->is_pressed());
+ Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
Vector2i coords = E.key;
@@ -674,9 +674,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
} else {
// Released
_stop_dragging();
- if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- rmb_erasing = false;
- }
+ drag_erasing = false;
}
CanvasItemEditor::get_singleton()->update_viewport();
@@ -730,7 +728,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Rect2i drawn_grid_rect;
if (drag_type == DRAG_TYPE_PICK) {
- // Draw the area being picvked.
+ // Draw the area being picked.
Rect2i rect = Rect2i(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos) - tile_map->world_to_map(drag_start_mouse_pos)).abs();
rect.size += Vector2i(1, 1);
for (int x = rect.position.x; x < rect.get_end().x; x++) {
@@ -789,25 +787,25 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single pattern.
- preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos);
+ preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos, erase_button->is_pressed());
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == line_tool_button || drag_type == DRAG_TYPE_LINE) {
if (drag_type == DRAG_TYPE_NONE) {
// Preview for a single pattern.
- preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos);
+ preview = _draw_line(drag_last_mouse_pos, drag_last_mouse_pos, drag_last_mouse_pos, erase_button->is_pressed());
expand_grid = true;
} else if (drag_type == DRAG_TYPE_LINE) {
// Preview for a line pattern.
- preview = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, drag_last_mouse_pos);
+ preview = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, drag_last_mouse_pos, drag_erasing);
expand_grid = true;
}
} else if (drag_type == DRAG_TYPE_RECT) {
// Preview for a rect pattern.
- preview = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos));
+ preview = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos), drag_erasing);
expand_grid = true;
} else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a fill pattern.
- preview = _draw_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_continuous_checkbox->is_pressed());
+ preview = _draw_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed(), erase_button->is_pressed());
}
// Expand the grid if needed
@@ -855,7 +853,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Transform2D tile_xform;
tile_xform.set_origin(tile_map->map_to_world(E.key));
tile_xform.set_scale(tile_set->get_tile_size());
- if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
+ if (!(drag_erasing || erase_button->is_pressed()) && random_tile_checkbox->is_pressed()) {
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} else {
if (tile_set->has_source(E.value.source_id)) {
@@ -966,7 +964,7 @@ TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pa
return TileMapCell();
}
-Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos) {
+Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos, bool p_erase) {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return Map<Vector2i, TileMapCell>();
@@ -981,12 +979,12 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_
Ref<TileMapPattern> erase_pattern;
erase_pattern.instantiate();
erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
+ Ref<TileMapPattern> pattern = p_erase ? erase_pattern : selection_pattern;
Map<Vector2i, TileMapCell> output;
if (!pattern->is_empty()) {
// Paint the tiles on the tile map.
- if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
+ if (!p_erase && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(p_from_mouse_pos), tile_map->world_to_map(p_to_mouse_pos));
for (int i = 0; i < line.size(); i++) {
@@ -1015,7 +1013,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_line(Vector2 p_start_
return output;
}
-Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell) {
+Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return Map<Vector2i, TileMapCell>();
@@ -1034,7 +1032,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
Ref<TileMapPattern> erase_pattern;
erase_pattern.instantiate();
erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
+ Ref<TileMapPattern> pattern = p_erase ? erase_pattern : selection_pattern;
Map<Vector2i, TileMapCell> err_output;
ERR_FAIL_COND_V(pattern->is_empty(), err_output);
@@ -1046,7 +1044,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
Map<Vector2i, TileMapCell> output;
if (!pattern->is_empty()) {
- if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
+ if (!p_erase && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
for (int x = 0; x < rect.size.x; x++) {
for (int y = 0; y < rect.size.y; y++) {
@@ -1074,7 +1072,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_rect(Vector2i p_start
return output;
}
-Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous) {
+Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase) {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return Map<Vector2i, TileMapCell>();
@@ -1095,14 +1093,14 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
Ref<TileMapPattern> erase_pattern;
erase_pattern.instantiate();
erase_pattern->set_cell(Vector2i(0, 0), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
- Ref<TileMapPattern> pattern = _is_erasing() ? erase_pattern : selection_pattern;
+ Ref<TileMapPattern> pattern = p_erase ? erase_pattern : selection_pattern;
if (!pattern->is_empty()) {
- TileMapCell source = tile_map->get_cell(tile_map_layer, p_coords);
+ TileMapCell source_cell = tile_map->get_cell(tile_map_layer, p_coords);
// If we are filling empty tiles, compute the tilemap boundaries.
Rect2i boundaries;
- if (source.source_id == TileSet::INVALID_SOURCE) {
+ if (source_cell.source_id == TileSet::INVALID_SOURCE) {
boundaries = tile_map->get_used_rect();
}
@@ -1115,11 +1113,11 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
Vector2i coords = to_check.back()->get();
to_check.pop_back();
if (!already_checked.has(coords)) {
- if (source.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) &&
- source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
- source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
- (source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
- if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
+ if (source_cell.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) &&
+ source_cell.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
+ source_cell.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
+ (source_cell.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
+ if (!p_erase && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
output.insert(coords, _pick_random_tile(pattern));
} else {
@@ -1146,7 +1144,7 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
} else {
// Replace all tiles like the source.
TypedArray<Vector2i> to_check;
- if (source.source_id == TileSet::INVALID_SOURCE) {
+ if (source_cell.source_id == TileSet::INVALID_SOURCE) {
Rect2i rect = tile_map->get_used_rect();
if (rect.has_no_area()) {
rect = Rect2i(p_coords, Vector2i(1, 1));
@@ -1161,11 +1159,11 @@ Map<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vector2i
}
for (int i = 0; i < to_check.size(); i++) {
Vector2i coords = to_check[i];
- if (source.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) &&
- source.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
- source.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
- (source.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
- if (!_is_erasing() && random_tile_checkbox->is_pressed()) {
+ if (source_cell.source_id == tile_map->get_cell_source_id(tile_map_layer, coords) &&
+ source_cell.get_atlas_coords() == tile_map->get_cell_atlas_coords(tile_map_layer, coords) &&
+ source_cell.alternative_tile == tile_map->get_cell_alternative_tile(tile_map_layer, coords) &&
+ (source_cell.source_id != TileSet::INVALID_SOURCE || boundaries.has_point(coords))) {
+ if (!p_erase && random_tile_checkbox->is_pressed()) {
// Paint a random tile.
output.insert(coords, _pick_random_tile(pattern));
} else {
@@ -1338,10 +1336,10 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->commit_action(false);
} break;
case DRAG_TYPE_LINE: {
- Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, mpos);
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_start_mouse_pos, mpos, drag_erasing);
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
@@ -1350,10 +1348,10 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_RECT: {
- Map<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos));
+ Map<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!_is_erasing() && E.value.source_id == TileSet::INVALID_SOURCE) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
@@ -1473,10 +1471,6 @@ void TileMapEditorTilesPlugin::_fix_invalid_tiles_in_tile_map_selection() {
}
}
-bool TileMapEditorTilesPlugin::_is_erasing() const {
- return erase_button->is_pressed() || rmb_erasing;
-}
-
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection() {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
@@ -2053,10 +2047,11 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
tools_settings->add_child(tools_settings_vsep_2);
// Continuous checkbox.
- bucket_continuous_checkbox = memnew(CheckBox);
- bucket_continuous_checkbox->set_flat(true);
- bucket_continuous_checkbox->set_text(TTR("Contiguous"));
- tools_settings->add_child(bucket_continuous_checkbox);
+ bucket_contiguous_checkbox = memnew(CheckBox);
+ bucket_contiguous_checkbox->set_flat(true);
+ bucket_contiguous_checkbox->set_text(TTR("Contiguous"));
+ bucket_contiguous_checkbox->set_pressed(true);
+ tools_settings->add_child(bucket_contiguous_checkbox);
// Random tile checkbox.
random_tile_checkbox = memnew(CheckBox);
@@ -2210,6 +2205,26 @@ void TileMapEditorTerrainsPlugin::_update_toolbar() {
tools_settings_vsep->show();
picker_button->show();
erase_button->show();
+ tools_settings_vsep_2->hide();
+ bucket_contiguous_checkbox->hide();
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ tools_settings_vsep_2->hide();
+ bucket_contiguous_checkbox->hide();
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ tools_settings_vsep_2->hide();
+ bucket_contiguous_checkbox->hide();
+ } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
+ tools_settings_vsep->show();
+ picker_button->show();
+ erase_button->show();
+ tools_settings_vsep_2->show();
+ bucket_contiguous_checkbox->show();
}
}
@@ -2321,23 +2336,224 @@ Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const Map
// Actually paint the tiles.
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
- output[E_to_paint.key] = tile_set->get_random_tile_from_pattern(p_terrain_set, E_to_paint.value);
+ output[E_to_paint.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E_to_paint.value);
}
// Use the WFC run for the output.
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : wfc_output) {
- output[E.key] = tile_set->get_random_tile_from_pattern(p_terrain_set, E.value);
+ output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ }
+
+ return output;
+}
+
+Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_line(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ TileSet::TerrainsPattern terrains_pattern;
+ if (p_erase) {
+ terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ } else {
+ terrains_pattern = selected_terrains_pattern;
+ }
+
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell);
+ Map<Vector2i, TileSet::TerrainsPattern> to_draw;
+ for (int i = 0; i < line.size(); i++) {
+ to_draw[line[i]] = terrains_pattern;
+ }
+ return _draw_terrains(to_draw, selected_terrain_set);
+}
+
+Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ TileSet::TerrainsPattern terrains_pattern;
+ if (p_erase) {
+ terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ } else {
+ terrains_pattern = selected_terrains_pattern;
+ }
+
+ Rect2i rect;
+ rect.set_position(p_start_cell);
+ rect.set_end(p_end_cell);
+ rect = rect.abs();
+
+ Map<Vector2i, TileSet::TerrainsPattern> to_draw;
+ for (int x = rect.position.x; x <= rect.get_end().x; x++) {
+ for (int y = rect.position.y; y <= rect.get_end().y; y++) {
+ to_draw[Vector2i(x, y)] = terrains_pattern;
+ }
}
+ return _draw_terrains(to_draw, selected_terrain_set);
+}
+
+Set<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Set<Vector2i>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Set<Vector2i>();
+ }
+
+ TileMapCell source_cell = tile_map->get_cell(tile_map_layer, p_coords);
+
+ TileSet::TerrainsPattern source_pattern(*tile_set, selected_terrain_set);
+ if (source_cell.source_id != TileSet::INVALID_SOURCE) {
+ TileData *tile_data = nullptr;
+ Ref<TileSetSource> source = tile_set->get_source(source_cell.source_id);
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(source_cell.get_atlas_coords(), source_cell.alternative_tile));
+ }
+ if (!tile_data) {
+ return Set<Vector2i>();
+ }
+ source_pattern = tile_data->get_terrains_pattern();
+ }
+
+ // If we are filling empty tiles, compute the tilemap boundaries.
+ Rect2i boundaries;
+ if (source_cell.source_id == TileSet::INVALID_SOURCE) {
+ boundaries = tile_map->get_used_rect();
+ }
+
+ Set<Vector2i> output;
+ if (p_contiguous) {
+ // Replace continuous tiles like the source.
+ Set<Vector2i> already_checked;
+ List<Vector2i> to_check;
+ to_check.push_back(p_coords);
+ while (!to_check.is_empty()) {
+ Vector2i coords = to_check.back()->get();
+ to_check.pop_back();
+ if (!already_checked.has(coords)) {
+ // Get the candidate cell pattern.
+ TileSet::TerrainsPattern candidate_pattern(*tile_set, selected_terrain_set);
+ if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
+ TileData *tile_data = nullptr;
+ Ref<TileSetSource> source = tile_set->get_source(tile_map->get_cell_source_id(tile_map_layer, coords));
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)));
+ }
+ if (tile_data) {
+ candidate_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+
+ // Draw.
+ if (candidate_pattern == source_pattern && (!source_pattern.is_erase_pattern() || boundaries.has_point(coords))) {
+ output.insert(coords);
+
+ // Get surrounding tiles (handles different tile shapes).
+ TypedArray<Vector2i> around = tile_map->get_surrounding_tiles(coords);
+ for (int i = 0; i < around.size(); i++) {
+ to_check.push_back(around[i]);
+ }
+ }
+ already_checked.insert(coords);
+ }
+ }
+ } else {
+ // Replace all tiles like the source.
+ TypedArray<Vector2i> to_check;
+ if (source_cell.source_id == TileSet::INVALID_SOURCE) {
+ Rect2i rect = tile_map->get_used_rect();
+ if (rect.has_no_area()) {
+ rect = Rect2i(p_coords, Vector2i(1, 1));
+ }
+ for (int x = boundaries.position.x; x < boundaries.get_end().x; x++) {
+ for (int y = boundaries.position.y; y < boundaries.get_end().y; y++) {
+ to_check.append(Vector2i(x, y));
+ }
+ }
+ } else {
+ to_check = tile_map->get_used_cells(tile_map_layer);
+ }
+ for (int i = 0; i < to_check.size(); i++) {
+ Vector2i coords = to_check[i];
+ // Get the candidate cell pattern.
+ TileSet::TerrainsPattern candidate_pattern;
+ if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
+ TileData *tile_data = nullptr;
+ Ref<TileSetSource> source = tile_set->get_source(tile_map->get_cell_source_id(tile_map_layer, coords));
+ Ref<TileSetAtlasSource> atlas_source = source;
+ if (atlas_source.is_valid()) {
+ tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords)));
+ }
+ if (tile_data) {
+ candidate_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ // Draw.
+ if (candidate_pattern == source_pattern && (!source_pattern.is_erase_pattern() || boundaries.has_point(coords))) {
+ output.insert(coords);
+ }
+ }
+ }
return output;
}
+Map<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return Map<Vector2i, TileMapCell>();
+ }
+
+ TileSet::TerrainsPattern terrains_pattern;
+ if (p_erase) {
+ terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ } else {
+ terrains_pattern = selected_terrains_pattern;
+ }
+
+ Set<Vector2i> cells_to_draw = _get_cells_for_bucket_fill(p_coords, p_contiguous);
+ Map<Vector2i, TileSet::TerrainsPattern> to_draw;
+ for (const Vector2i &coords : cells_to_draw) {
+ to_draw[coords] = terrains_pattern;
+ }
+
+ return _draw_terrains(to_draw, selected_terrain_set);
+}
+
void TileMapEditorTerrainsPlugin::_stop_dragging() {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return;
}
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position());
@@ -2345,12 +2561,6 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
case DRAG_TYPE_PICK: {
Vector2i coords = tile_map->world_to_map(mpos);
TileMapCell cell = tile_map->get_cell(tile_map_layer, coords);
-
- Ref<TileSet> tile_set = tile_map->get_tileset();
- if (!tile_set.is_valid()) {
- return;
- }
-
TileData *tile_data = nullptr;
Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
@@ -2360,17 +2570,19 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
}
if (tile_data) {
- Array terrains_pattern = tile_data->get_terrains_pattern();
+ TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
// Find the tree item for the right terrain set.
bool need_tree_item_switch = true;
TreeItem *tree_item = terrains_tree->get_selected();
+ int new_terrain_set = -1;
if (tree_item) {
Dictionary metadata_dict = tree_item->get_metadata(0);
if (metadata_dict.has("terrain_set") && metadata_dict.has("terrain_id")) {
int terrain_set = metadata_dict["terrain_set"];
int terrain_id = metadata_dict["terrain_id"];
if (per_terrain_terrains_patterns[terrain_set][terrain_id].has(terrains_pattern)) {
+ new_terrain_set = terrain_set;
need_tree_item_switch = false;
}
}
@@ -2384,6 +2596,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
int terrain_id = metadata_dict["terrain_id"];
if (per_terrain_terrains_patterns[terrain_set][terrain_id].has(terrains_pattern)) {
// Found
+ new_terrain_set = terrain_set;
tree_item->select(0);
_update_tiles_list();
break;
@@ -2396,15 +2609,9 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
if (tree_item) {
for (int i = 0; i < terrains_tile_list->get_item_count(); i++) {
Dictionary metadata_dict = terrains_tile_list->get_item_metadata(i);
- TileSet::TerrainsPattern in_meta_terrains_pattern = metadata_dict["terrains_pattern"];
- bool equals = true;
- for (int j = 0; j < terrains_pattern.size(); j++) {
- if (terrains_pattern[j] != in_meta_terrains_pattern[j]) {
- equals = false;
- break;
- }
- }
- if (equals) {
+ TileSet::TerrainsPattern in_meta_terrains_pattern(*tile_set, new_terrain_set);
+ in_meta_terrains_pattern.set_terrains_from_array(metadata_dict["terrains_pattern"]);
+ if (in_meta_terrains_pattern == terrains_pattern) {
terrains_tile_list->select(i);
break;
}
@@ -2423,12 +2630,82 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
}
undo_redo->commit_action(false);
} break;
+ case DRAG_TYPE_LINE: {
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ undo_redo->create_action(TTR("Paint terrain"));
+ for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
+ continue;
+ }
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key));
+ }
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_RECT: {
+ Map<Vector2i, TileMapCell> to_draw = _draw_rect(tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ undo_redo->create_action(TTR("Paint terrain"));
+ for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
+ continue;
+ }
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key));
+ }
+ undo_redo->commit_action();
+ } break;
+ case DRAG_TYPE_BUCKET: {
+ undo_redo->create_action(TTR("Paint terrain"));
+ for (const KeyValue<Vector2i, TileMapCell> &E : drag_modified) {
+ undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key));
+ undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
+ }
+ undo_redo->commit_action(false);
+ } break;
+
default:
break;
}
drag_type = DRAG_TYPE_NONE;
}
+void TileMapEditorTerrainsPlugin::_mouse_exited_viewport() {
+ has_mouse = false;
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+void TileMapEditorTerrainsPlugin::_update_selection() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ // Get the selected terrain.
+ selected_terrains_pattern = TileSet::TerrainsPattern();
+ selected_terrain_set = -1;
+
+ TreeItem *selected_tree_item = terrains_tree->get_selected();
+ if (selected_tree_item && selected_tree_item->get_metadata(0)) {
+ Dictionary metadata_dict = selected_tree_item->get_metadata(0);
+ // Selected terrain
+ selected_terrain_set = metadata_dict["terrain_set"];
+
+ // Selected tile
+ if (erase_button->is_pressed()) {
+ selected_terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ } else if (terrains_tile_list->is_anything_selected()) {
+ metadata_dict = terrains_tile_list->get_item_metadata(terrains_tile_list->get_selected_items()[0]);
+ selected_terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ selected_terrains_pattern.set_terrains_from_array(metadata_dict["terrains_pattern"]);
+ }
+ }
+}
+
bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
if (!main_vbox_container->is_visible_in_tree()) {
// If the bottom editor is not visible, we ignore inputs.
@@ -2454,46 +2731,19 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
}
ERR_FAIL_COND_V(tile_map_layer >= tile_map->get_layers_count(), false);
- // Get the selected terrain.
- TileSet::TerrainsPattern selected_terrains_pattern;
- int selected_terrain_set = -1;
-
- TreeItem *selected_tree_item = terrains_tree->get_selected();
- if (selected_tree_item && selected_tree_item->get_metadata(0)) {
- Dictionary metadata_dict = selected_tree_item->get_metadata(0);
- // Selected terrain
- selected_terrain_set = metadata_dict["terrain_set"];
-
- // Selected tile
- if (erase_button->is_pressed()) {
- selected_terrains_pattern.clear();
- for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
- if (tile_set->is_valid_peering_bit_terrain(selected_terrain_set, side)) {
- selected_terrains_pattern.push_back(-1);
- }
- }
- } else if (terrains_tile_list->is_anything_selected()) {
- metadata_dict = terrains_tile_list->get_item_metadata(terrains_tile_list->get_selected_items()[0]);
- selected_terrains_pattern = metadata_dict["terrains_pattern"];
- }
- }
+ _update_selection();
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
+ has_mouse = true;
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(mm->get_position());
switch (drag_type) {
case DRAG_TYPE_PAINT: {
if (selected_terrain_set >= 0) {
- Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
- Map<Vector2i, TileSet::TerrainsPattern> to_draw;
- for (int i = 0; i < line.size(); i++) {
- to_draw[line[i]] = selected_terrains_pattern;
- }
- Map<Vector2i, TileMapCell> modified = _draw_terrains(to_draw, selected_terrain_set);
- for (const KeyValue<Vector2i, TileMapCell> &E : modified) {
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos), drag_erasing);
+ for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
if (!drag_modified.has(E.key)) {
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
}
@@ -2512,35 +2762,79 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
+ has_mouse = true;
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(mb->get_position());
- if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (mb->is_pressed()) {
// Pressed
+ if (erase_button->is_pressed() || mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
+ drag_erasing = true;
+ }
+
if (picker_button->is_pressed()) {
drag_type = DRAG_TYPE_PICK;
} else {
// Paint otherwise.
- if (selected_terrain_set >= 0 && !selected_terrains_pattern.is_empty() && tool_buttons_group->get_pressed_button() == paint_tool_button) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
+ if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
+ return true;
+ }
+
drag_type = DRAG_TYPE_PAINT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
-
- Map<Vector2i, TileSet::TerrainsPattern> terrains_to_draw;
- terrains_to_draw[tile_map->world_to_map(mpos)] = selected_terrains_pattern;
-
- Map<Vector2i, TileMapCell> to_draw = _draw_terrains(terrains_to_draw, selected_terrain_set);
+ Vector2i cell = tile_map->world_to_map(mpos);
+ Map<Vector2i, TileMapCell> to_draw = _draw_line(cell, cell, drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && !Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
+ if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
+ return true;
+ }
+ drag_type = DRAG_TYPE_LINE;
+ drag_start_mouse_pos = mpos;
+ drag_modified.clear();
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(KEY_SHIFT) && Input::get_singleton()->is_key_pressed(KEY_CTRL))) {
+ if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
+ return true;
+ }
+ drag_type = DRAG_TYPE_RECT;
+ drag_start_mouse_pos = mpos;
+ drag_modified.clear();
+ } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
+ if (selected_terrain_set < 0 || !selected_terrains_pattern.is_valid()) {
+ return true;
+ }
+ drag_type = DRAG_TYPE_BUCKET;
+ drag_start_mouse_pos = mpos;
+ drag_modified.clear();
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos));
+ for (int i = 0; i < line.size(); i++) {
+ if (!drag_modified.has(line[i])) {
+ Map<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
+ for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
+ continue;
+ }
+ Vector2i coords = E.key;
+ if (!drag_modified.has(coords)) {
+ drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
+ }
+ tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
+ }
+ }
+ }
}
}
} else {
// Released
_stop_dragging();
+ drag_erasing = false;
}
CanvasItemEditor::get_singleton()->update_viewport();
@@ -2553,6 +2847,135 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
return false;
}
+void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ if (tile_map_layer < 0) {
+ return;
+ }
+ ERR_FAIL_INDEX(tile_map_layer, tile_map->get_layers_count());
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ if (!tile_map->is_visible_in_tree()) {
+ return;
+ }
+
+ Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
+ Vector2i tile_shape_size = tile_set->get_tile_size();
+
+ // Handle the preview of the tiles to be placed.
+ if (main_vbox_container->is_visible_in_tree() && has_mouse) { // Only if the tilemap editor is opened and the viewport is hovered.
+ Set<Vector2i> preview;
+ Rect2i drawn_grid_rect;
+
+ if (drag_type == DRAG_TYPE_PICK) {
+ // Draw the area being picked.
+ Vector2i coords = tile_map->world_to_map(drag_last_mouse_pos);
+ if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_scale(tile_shape_size);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
+ }
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) {
+ bool expand_grid = false;
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
+ // Preview for a single tile.
+ preview.insert(tile_map->world_to_map(drag_last_mouse_pos));
+ expand_grid = true;
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || drag_type == DRAG_TYPE_LINE) {
+ if (drag_type == DRAG_TYPE_NONE) {
+ // Preview for a single tile.
+ preview.insert(tile_map->world_to_map(drag_last_mouse_pos));
+ } else if (drag_type == DRAG_TYPE_LINE) {
+ // Preview for a line.
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_start_mouse_pos), tile_map->world_to_map(drag_last_mouse_pos));
+ for (int i = 0; i < line.size(); i++) {
+ preview.insert(line[i]);
+ }
+ expand_grid = true;
+ }
+ } else if (drag_type == DRAG_TYPE_RECT) {
+ // Preview for a rect.
+ Rect2i rect;
+ rect.set_position(tile_map->world_to_map(drag_start_mouse_pos));
+ rect.set_end(tile_map->world_to_map(drag_last_mouse_pos));
+ rect = rect.abs();
+
+ Map<Vector2i, TileSet::TerrainsPattern> to_draw;
+ for (int x = rect.position.x; x <= rect.get_end().x; x++) {
+ for (int y = rect.position.y; y <= rect.get_end().y; y++) {
+ preview.insert(Vector2i(x, y));
+ }
+ }
+ expand_grid = true;
+ } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button && drag_type == DRAG_TYPE_NONE) {
+ // Preview for a fill.
+ preview = _get_cells_for_bucket_fill(tile_map->world_to_map(drag_last_mouse_pos), bucket_contiguous_checkbox->is_pressed());
+ }
+
+ // Expand the grid if needed
+ if (expand_grid && !preview.is_empty()) {
+ drawn_grid_rect = Rect2i(preview.front()->get(), Vector2i(1, 1));
+ for (const Vector2i &E : preview) {
+ drawn_grid_rect.expand_to(E);
+ }
+ }
+ }
+
+ if (!preview.is_empty()) {
+ const int fading = 5;
+
+ // Draw the lines of the grid behind the preview.
+ bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid");
+ if (display_grid) {
+ Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ if (drawn_grid_rect.size.x > 0 && drawn_grid_rect.size.y > 0) {
+ drawn_grid_rect = drawn_grid_rect.grow(fading);
+ for (int x = drawn_grid_rect.position.x; x < (drawn_grid_rect.position.x + drawn_grid_rect.size.x); x++) {
+ for (int y = drawn_grid_rect.position.y; y < (drawn_grid_rect.position.y + drawn_grid_rect.size.y); y++) {
+ Vector2i pos_in_rect = Vector2i(x, y) - drawn_grid_rect.position;
+
+ // Fade out the border of the grid.
+ float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f);
+ float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f);
+ float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f);
+ float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
+ float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
+
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_scale(tile_shape_size);
+ Color color = grid_color;
+ color.a = color.a * opacity;
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, false);
+ }
+ }
+ }
+ }
+
+ // Draw the preview.
+ for (const Vector2i &E : preview) {
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(E));
+ tile_xform.set_scale(tile_set->get_tile_size());
+ if (drag_erasing || erase_button->is_pressed()) {
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(0.0, 0.0, 0.0, 0.5), true);
+ } else {
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
+ }
+ }
+ }
+ }
+}
+
void TileMapEditorTerrainsPlugin::_update_terrains_cache() {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
@@ -2595,12 +3018,14 @@ void TileMapEditorTerrainsPlugin::_update_terrains_cache() {
cell.alternative_tile = alternative_id;
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
-
// Terrain bits.
- for (int i = 0; i < terrains_pattern.size(); i++) {
- int terrain = terrains_pattern[i];
- if (terrain >= 0 && terrain < (int)per_terrain_terrains_patterns[terrain_set].size()) {
- per_terrain_terrains_patterns[terrain_set][terrain].insert(terrains_pattern);
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ int terrain = terrains_pattern.get_terrain(bit);
+ if (terrain >= 0 && terrain < (int)per_terrain_terrains_patterns[terrain_set].size()) {
+ per_terrain_terrains_patterns[terrain_set][terrain].insert(terrains_pattern);
+ }
}
}
}
@@ -2686,8 +3111,9 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
// Count the number of matching sides/terrains.
int count = 0;
- for (int i = 0; i < E->get().size(); i++) {
- if (int(E->get()[i]) == selected_terrain_id) {
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
+ if (tile_set->is_valid_peering_bit_terrain(selected_terrain_set, bit) && E->get().get_terrain(bit) == selected_terrain_id) {
count++;
}
}
@@ -2733,7 +3159,7 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
terrains_tile_list->set_item_icon_region(item_index, region);
terrains_tile_list->set_item_icon_transposed(item_index, transpose);
Dictionary list_metadata_dict;
- list_metadata_dict["terrains_pattern"] = terrains_pattern;
+ list_metadata_dict["terrains_pattern"] = terrains_pattern.get_terrains_as_array();
terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
}
}
@@ -2745,6 +3171,10 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
void TileMapEditorTerrainsPlugin::_update_theme() {
paint_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ line_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
+ rect_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Rectangle"), SNAME("EditorIcons")));
+ bucket_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Bucket"), SNAME("EditorIcons")));
+
picker_button->set_icon(main_vbox_container->get_theme_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
erase_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
}
@@ -2804,6 +3234,30 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
+ line_tool_button = memnew(Button);
+ line_tool_button->set_flat(true);
+ line_tool_button->set_toggle_mode(true);
+ line_tool_button->set_button_group(tool_buttons_group);
+ line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", KEY_L));
+ line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(line_tool_button);
+
+ rect_tool_button = memnew(Button);
+ rect_tool_button->set_flat(true);
+ rect_tool_button->set_toggle_mode(true);
+ rect_tool_button->set_button_group(tool_buttons_group);
+ rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", KEY_R));
+ rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(rect_tool_button);
+
+ bucket_tool_button = memnew(Button);
+ bucket_tool_button->set_flat(true);
+ bucket_tool_button->set_toggle_mode(true);
+ bucket_tool_button->set_button_group(tool_buttons_group);
+ bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", KEY_B));
+ bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
+ tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
+
toolbar->add_child(tilemap_tiles_tools_buttons);
// -- TileMap tool settings --
@@ -2828,6 +3282,17 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", KEY_E));
erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
+
+ // Separator 2.
+ tools_settings_vsep_2 = memnew(VSeparator);
+ tools_settings->add_child(tools_settings_vsep_2);
+
+ // Continuous checkbox.
+ bucket_contiguous_checkbox = memnew(CheckBox);
+ bucket_contiguous_checkbox->set_flat(true);
+ bucket_contiguous_checkbox->set_text(TTR("Contiguous"));
+ bucket_contiguous_checkbox->set_pressed(true);
+ tools_settings->add_child(bucket_contiguous_checkbox);
}
TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() {
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index 0513a7b365..f462119727 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -75,14 +75,15 @@ private:
Button *line_tool_button;
Button *rect_tool_button;
Button *bucket_tool_button;
- Button *picker_button;
HBoxContainer *tools_settings;
+
VSeparator *tools_settings_vsep;
+ Button *picker_button;
Button *erase_button;
- CheckBox *bucket_continuous_checkbox;
VSeparator *tools_settings_vsep_2;
+ CheckBox *bucket_contiguous_checkbox;
CheckBox *random_tile_checkbox;
float scattering = 0.0;
Label *scatter_label;
@@ -108,17 +109,16 @@ private:
DRAG_TYPE_CLIPBOARD_PASTE,
};
DragType drag_type = DRAG_TYPE_NONE;
+ bool drag_erasing = false;
Vector2 drag_start_mouse_pos;
Vector2 drag_last_mouse_pos;
Map<Vector2i, TileMapCell> drag_modified;
- bool rmb_erasing = false;
TileMapCell _pick_random_tile(Ref<TileMapPattern> p_pattern);
- Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos);
- Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell);
- Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous);
+ Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos, bool p_erase);
+ Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
+ Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase);
void _stop_dragging();
- bool _is_erasing() const;
///// Selection system. /////
Set<Vector2i> tile_map_selection;
@@ -220,32 +220,53 @@ private:
Ref<ButtonGroup> tool_buttons_group;
Button *paint_tool_button;
+ Button *line_tool_button;
+ Button *rect_tool_button;
+ Button *bucket_tool_button;
HBoxContainer *tools_settings;
+
VSeparator *tools_settings_vsep;
Button *picker_button;
Button *erase_button;
+ VSeparator *tools_settings_vsep_2;
+ CheckBox *bucket_contiguous_checkbox;
void _update_toolbar();
// Main vbox.
VBoxContainer *main_vbox_container;
// TileMap editing.
+ bool has_mouse = false;
+ void _mouse_exited_viewport();
+
enum DragType {
DRAG_TYPE_NONE = 0,
DRAG_TYPE_PAINT,
+ DRAG_TYPE_LINE,
+ DRAG_TYPE_RECT,
+ DRAG_TYPE_BUCKET,
DRAG_TYPE_PICK,
};
DragType drag_type = DRAG_TYPE_NONE;
+ bool drag_erasing = false;
Vector2 drag_start_mouse_pos;
Vector2 drag_last_mouse_pos;
Map<Vector2i, TileMapCell> drag_modified;
// Painting
Map<Vector2i, TileMapCell> _draw_terrains(const Map<Vector2i, TileSet::TerrainsPattern> &p_to_paint, int p_terrain_set) const;
+ Map<Vector2i, TileMapCell> _draw_line(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
+ Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
+ Set<Vector2i> _get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous);
+ Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase);
void _stop_dragging();
+ int selected_terrain_set = -1;
+ TileSet::TerrainsPattern selected_terrains_pattern;
+ void _update_selection();
+
// Bottom panel.
Tree *terrains_tree;
ItemList *terrains_tile_list;
@@ -265,7 +286,7 @@ private:
public:
virtual Vector<TabData> get_tabs() const override;
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
- //virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
TileMapEditorTerrainsPlugin();
~TileMapEditorTerrainsPlugin();
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 0fbb9a98c7..915ce50836 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -41,10 +41,10 @@
TileSetEditor *TileSetEditor::singleton = nullptr;
-void TileSetEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+void TileSetEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
ERR_FAIL_COND(!tile_set.is_valid());
- if (!can_drop_data_fw(p_point, p_data, p_from)) {
+ if (!_can_drop_data_fw(p_point, p_data, p_from)) {
return;
}
@@ -81,7 +81,7 @@ void TileSetEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, C
}
}
-bool TileSetEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+bool TileSetEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
ERR_FAIL_COND_V(!tile_set.is_valid(), false);
if (p_from == sources_list) {
@@ -608,8 +608,8 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
}
void TileSetEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetEditor::_can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::_drop_data_fw);
}
void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index cda38760cf..58312ce3df 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -59,6 +59,9 @@ private:
UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+
void _update_sources_list(int force_selected_id = -1);
// Sources management.
@@ -98,9 +101,6 @@ public:
void edit(Ref<TileSet> p_tile_set);
- void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
-
TileSetEditor();
~TileSetEditor();
};
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 dc26d380b8..d687d9651d 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -385,8 +385,8 @@ void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetS
_update_tile_inspector();
}
-void TileSetScenesCollectionSourceEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- if (!can_drop_data_fw(p_point, p_data, p_from)) {
+void TileSetScenesCollectionSourceEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ if (!_can_drop_data_fw(p_point, p_data, p_from)) {
return;
}
@@ -412,7 +412,7 @@ void TileSetScenesCollectionSourceEditor::drop_data_fw(const Point2 &p_point, co
}
}
-bool TileSetScenesCollectionSourceEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+bool TileSetScenesCollectionSourceEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
if (p_from == scene_tiles_list) {
Dictionary d = p_data;
@@ -447,8 +447,8 @@ void TileSetScenesCollectionSourceEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileSetScenesCollectionSourceEditor::_scene_thumbnail_done);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &TileSetScenesCollectionSourceEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &TileSetScenesCollectionSourceEditor::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_drop_data_fw);
}
TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
index 3be7bee714..4e33128be5 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
@@ -125,14 +125,15 @@ private:
void _update_scenes_list();
void _update_action_buttons();
+ void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id);
- void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
TileSetScenesCollectionSourceEditor();
~TileSetScenesCollectionSourceEditor();
};
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 09ca1f7608..c06eafae50 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -104,7 +104,6 @@ void VisualShaderGraphPlugin::_bind_methods() {
ClassDB::bind_method("connect_nodes", &VisualShaderGraphPlugin::connect_nodes);
ClassDB::bind_method("disconnect_nodes", &VisualShaderGraphPlugin::disconnect_nodes);
ClassDB::bind_method("set_node_position", &VisualShaderGraphPlugin::set_node_position);
- ClassDB::bind_method("set_node_size", &VisualShaderGraphPlugin::set_node_size);
ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);
ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);
ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);
@@ -292,12 +291,6 @@ void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p
}
}
-void VisualShaderGraphPlugin::set_node_size(VisualShader::Type p_type, int p_id, const Vector2 &p_size) {
- if (visual_shader->get_shader_type() == p_type && links.has(p_id)) {
- links[p_id].graph_node->set_size(p_size);
- }
-}
-
bool VisualShaderGraphPlugin::is_preview_visible(int p_id) const {
return links[p_id].preview_visible;
}
@@ -1047,7 +1040,6 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
hide();
} else {
if (changed) { // to avoid tree collapse
- _clear_buffer();
_update_options_menu();
_update_preview();
_update_graph();
@@ -1246,7 +1238,7 @@ void VisualShaderEditor::_update_options_menu() {
Color unsupported_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
Color supported_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
- static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES2";
+ static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "opengl3";
Map<String, TreeItem *> folders;
@@ -1426,13 +1418,23 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_standard->set_visible(false);
edit_type_particles->set_visible(false);
edit_type_sky->set_visible(true);
+ edit_type_fog->set_visible(false);
edit_type = edit_type_sky;
custom_mode_box->set_visible(false);
mode = MODE_FLAGS_SKY;
+ } else if (p_which == VisualShader::MODE_FOG) {
+ edit_type_standard->set_visible(false);
+ edit_type_particles->set_visible(false);
+ edit_type_sky->set_visible(false);
+ edit_type_fog->set_visible(true);
+ edit_type = edit_type_fog;
+ custom_mode_box->set_visible(false);
+ mode = MODE_FLAGS_FOG;
} else if (p_which == VisualShader::MODE_PARTICLES) {
edit_type_standard->set_visible(false);
edit_type_particles->set_visible(true);
edit_type_sky->set_visible(false);
+ edit_type_fog->set_visible(false);
edit_type = edit_type_particles;
if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) {
custom_mode_box->set_visible(false);
@@ -1444,6 +1446,7 @@ void VisualShaderEditor::_set_mode(int p_which) {
edit_type_particles->set_visible(false);
edit_type_standard->set_visible(true);
edit_type_sky->set_visible(false);
+ edit_type_fog->set_visible(false);
edit_type = edit_type_standard;
custom_mode_box->set_visible(false);
mode = MODE_FLAGS_SPATIAL_CANVASITEM;
@@ -1601,6 +1604,8 @@ VisualShader::Type VisualShaderEditor::get_current_shader_type() const {
type = VisualShader::Type(edit_type->get_selected() + 3 + (custom_mode_enabled ? 3 : 0));
} else if (mode & MODE_FLAGS_SKY) {
type = VisualShader::Type(edit_type->get_selected() + 8);
+ } else if (mode & MODE_FLAGS_FOG) {
+ type = VisualShader::Type(edit_type->get_selected() + 9);
} else {
type = VisualShader::Type(edit_type->get_selected());
}
@@ -2752,9 +2757,6 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, F), F);
undo_redo->add_undo_method(graph_plugin.ptr(), "add_node", type, F);
- undo_redo->add_do_method(this, "_clear_buffer");
- undo_redo->add_undo_method(this, "_clear_buffer");
-
// restore size, inputs and outputs if node is group
VisualShaderNodeGroupBase *group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
if (group) {
@@ -3090,13 +3092,15 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
selected_float_constant = -1;
}
- if (to_change.is_empty() && copy_nodes_buffer.is_empty()) {
+ if (to_change.is_empty() && copy_items_buffer.is_empty()) {
_show_members_dialog(true);
} else {
+ popup_menu->set_item_disabled(NodeMenuOptions::CUT, to_change.is_empty());
popup_menu->set_item_disabled(NodeMenuOptions::COPY, to_change.is_empty());
- popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_nodes_buffer.is_empty());
+ popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_items_buffer.is_empty());
popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.is_empty());
popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.is_empty());
+ popup_menu->set_item_disabled(NodeMenuOptions::CLEAR_COPY_BUFFER, copy_items_buffer.is_empty());
int temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR2);
if (temp != -1) {
@@ -3207,10 +3211,7 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos, VisualShaderNod
void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
Ref<InputEventKey> ie = p_ie;
- if (ie.is_valid() && (ie->get_keycode() == KEY_UP ||
- ie->get_keycode() == KEY_DOWN ||
- ie->get_keycode() == KEY_ENTER ||
- ie->get_keycode() == KEY_KP_ENTER)) {
+ if (ie.is_valid() && (ie->get_keycode() == KEY_UP || ie->get_keycode() == KEY_DOWN || ie->get_keycode() == KEY_ENTER || ie->get_keycode() == KEY_KP_ENTER)) {
members->gui_input(ie);
node_filter->accept_event();
}
@@ -3319,69 +3320,88 @@ void VisualShaderEditor::_node_changed(int p_id) {
}
}
-void VisualShaderEditor::_dup_update_excluded(int p_type, Set<int> &r_excluded) {
- r_excluded.clear();
- VisualShader::Type type = (VisualShader::Type)p_type;
-
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- int id = String(gn->get_name()).to_int();
- Ref<VisualShaderNode> node = visual_shader->get_node(type, id);
- Ref<VisualShaderNodeOutput> output = node;
- if (output.is_valid()) {
- r_excluded.insert(id);
- continue;
- }
- r_excluded.insert(id);
- }
- }
-}
-
-void VisualShaderEditor::_dup_copy_nodes(int p_type, List<int> &r_nodes, Set<int> &r_excluded) {
+void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, List<VisualShader::Connection> &r_connections) {
VisualShader::Type type = (VisualShader::Type)p_type;
selection_center.x = 0.0f;
selection_center.y = 0.0f;
+ Set<int> nodes;
+
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
if (gn) {
int id = String(gn->get_name()).to_int();
+
Ref<VisualShaderNode> node = visual_shader->get_node(type, id);
Ref<VisualShaderNodeOutput> output = node;
if (output.is_valid()) { // can't duplicate output
- r_excluded.insert(id);
continue;
}
+
if (node.is_valid() && gn->is_selected()) {
Vector2 pos = visual_shader->get_node_position(type, id);
selection_center += pos;
- r_nodes.push_back(id);
+
+ CopyItem item;
+ item.id = id;
+ item.node = visual_shader->get_node(type, id)->duplicate();
+ item.position = visual_shader->get_node_position(type, id);
+
+ Ref<VisualShaderNodeResizableBase> resizable_base = node;
+ if (resizable_base.is_valid()) {
+ item.size = resizable_base->get_size();
+ }
+
+ Ref<VisualShaderNodeGroupBase> group = node;
+ if (group.is_valid()) {
+ item.group_inputs = group->get_inputs();
+ item.group_outputs = group->get_outputs();
+ }
+
+ Ref<VisualShaderNodeExpression> expression = node;
+ if (expression.is_valid()) {
+ item.expression = expression->get_expression();
+ }
+
+ r_items.push_back(item);
+
+ nodes.insert(id);
}
- r_excluded.insert(id);
}
}
- selection_center /= (float)r_nodes.size();
+ List<VisualShader::Connection> connections;
+ visual_shader->get_node_connections(type, &connections);
+
+ for (const VisualShader::Connection &E : connections) {
+ if (nodes.has(E.from_node) && nodes.has(E.to_node)) {
+ r_connections.push_back(E);
+ }
+ }
+
+ selection_center /= (float)r_items.size();
}
-void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<int> &r_nodes, Set<int> &r_excluded, const Vector2 &p_offset, bool p_select) {
+void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate) {
+ if (p_duplicate) {
+ undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));
+ } else {
+ undo_redo->create_action(TTR("Paste VisualShader Node(s)"));
+ }
+
VisualShader::Type type = (VisualShader::Type)p_type;
- VisualShader::Type pasted_type = (VisualShader::Type)p_pasted_type;
int base_id = visual_shader->get_valid_node_id(type);
int id_from = base_id;
Map<int, int> connection_remap;
Set<int> unsupported_set;
+ Set<int> added_set;
- for (int &E : r_nodes) {
- connection_remap[E] = id_from;
- Ref<VisualShaderNode> node = visual_shader->get_node(pasted_type, E);
-
+ for (CopyItem &item : r_items) {
bool unsupported = false;
for (int i = 0; i < add_options.size(); i++) {
- if (add_options[i].type == node->get_class_name()) {
+ if (add_options[i].type == item.node->get_class_name()) {
if (!_is_available(add_options[i].mode)) {
unsupported = true;
}
@@ -3389,48 +3409,47 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<in
}
}
if (unsupported) {
- unsupported_set.insert(E);
+ unsupported_set.insert(item.id);
continue;
}
+ connection_remap[item.id] = id_from;
+ Ref<VisualShaderNode> node = item.node->duplicate();
- Ref<VisualShaderNode> dupli = node->duplicate();
-
- undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, dupli, visual_shader->get_node_position(pasted_type, E) + p_offset, id_from);
- undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_from);
+ Ref<VisualShaderNodeResizableBase> resizable_base = Object::cast_to<VisualShaderNodeResizableBase>(node.ptr());
+ if (resizable_base.is_valid()) {
+ undo_redo->add_do_method(node.ptr(), "set_size", item.size);
+ }
- // duplicate size, inputs and outputs if node is group
Ref<VisualShaderNodeGroupBase> group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
- if (!group.is_null()) {
- undo_redo->add_do_method(dupli.ptr(), "set_size", group->get_size());
- undo_redo->add_do_method(graph_plugin.ptr(), "set_node_size", type, id_from, group->get_size());
- undo_redo->add_do_method(dupli.ptr(), "set_inputs", group->get_inputs());
- undo_redo->add_do_method(dupli.ptr(), "set_outputs", group->get_outputs());
+ if (group.is_valid()) {
+ undo_redo->add_do_method(node.ptr(), "set_inputs", item.group_inputs);
+ undo_redo->add_do_method(node.ptr(), "set_outputs", item.group_outputs);
}
- // duplicate expression text if node is expression
+
Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
- if (!expression.is_null()) {
- undo_redo->add_do_method(dupli.ptr(), "set_expression", expression->get_expression());
+ if (expression.is_valid()) {
+ undo_redo->add_do_method(node.ptr(), "set_expression", item.expression);
}
+ undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, node, item.position + p_offset, id_from);
+ undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_from);
+
+ added_set.insert(id_from);
id_from++;
}
- List<VisualShader::Connection> conns;
- visual_shader->get_node_connections(pasted_type, &conns);
-
- for (const VisualShader::Connection &E : conns) {
+ for (const VisualShader::Connection &E : p_connections) {
if (unsupported_set.has(E.from_node) || unsupported_set.has(E.to_node)) {
continue;
}
- if (connection_remap.has(E.from_node) && connection_remap.has(E.to_node)) {
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);
- }
+
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, connection_remap[E.from_node], E.from_port, connection_remap[E.to_node], E.to_port);
}
id_from = base_id;
- for (int i = 0; i < r_nodes.size(); i++) {
+ for (int i = 0; i < r_items.size(); i++) {
undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from);
undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_from);
id_from++;
@@ -3438,54 +3457,61 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<in
undo_redo->commit_action();
- if (p_select) {
- // reselect duplicated nodes by excluding the other ones
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- int id = String(gn->get_name()).to_int();
- if (!r_excluded.has(id)) {
- gn->set_selected(true);
- } else {
- gn->set_selected(false);
- }
+ // reselect nodes by excluding the other ones
+ for (int i = 0; i < graph->get_child_count(); i++) {
+ GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
+ if (gn) {
+ int id = String(gn->get_name()).to_int();
+ if (added_set.has(id)) {
+ gn->set_selected(true);
+ } else {
+ gn->set_selected(false);
}
}
}
}
-void VisualShaderEditor::_clear_buffer() {
- copy_nodes_buffer.clear();
- copy_nodes_excluded_buffer.clear();
+void VisualShaderEditor::_clear_copy_buffer() {
+ copy_items_buffer.clear();
+ copy_connections_buffer.clear();
}
void VisualShaderEditor::_duplicate_nodes() {
int type = get_current_shader_type();
- List<int> nodes;
- Set<int> excluded;
+ List<CopyItem> items;
+ List<VisualShader::Connection> connections;
- _dup_copy_nodes(type, nodes, excluded);
+ _dup_copy_nodes(type, items, connections);
- if (nodes.is_empty()) {
+ if (items.is_empty()) {
return;
}
- undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));
-
- _dup_paste_nodes(type, type, nodes, excluded, Vector2(10, 10) * EDSCALE, true);
+ _dup_paste_nodes(type, items, connections, Vector2(10, 10) * EDSCALE, true);
}
-void VisualShaderEditor::_copy_nodes() {
- copy_type = get_current_shader_type();
+void VisualShaderEditor::_copy_nodes(bool p_cut) {
+ _clear_copy_buffer();
+
+ _dup_copy_nodes(get_current_shader_type(), copy_items_buffer, copy_connections_buffer);
+
+ if (p_cut) {
+ undo_redo->create_action(TTR("Cut VisualShader Node(s)"));
+
+ List<int> ids;
+ for (const CopyItem &E : copy_items_buffer) {
+ ids.push_back(E.id);
+ }
- _clear_buffer();
+ _delete_nodes(get_current_shader_type(), ids);
- _dup_copy_nodes(copy_type, copy_nodes_buffer, copy_nodes_excluded_buffer);
+ undo_redo->commit_action();
+ }
}
void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2 &p_custom_position) {
- if (copy_nodes_buffer.is_empty()) {
+ if (copy_items_buffer.is_empty()) {
return;
}
@@ -3500,11 +3526,7 @@ void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2
mpos = graph->get_local_mouse_position();
}
- undo_redo->create_action(TTR("Paste VisualShader Node(s)"));
-
- _dup_paste_nodes(type, copy_type, copy_nodes_buffer, copy_nodes_excluded_buffer, (graph->get_scroll_ofs() / scale + mpos / scale - selection_center), false);
-
- _dup_update_excluded(type, copy_nodes_excluded_buffer); // to prevent selection of previous copies at new paste
+ _dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_ofs() / scale + mpos / scale - selection_center, false);
}
void VisualShaderEditor::_mode_selected(int p_id) {
@@ -3523,11 +3545,15 @@ void VisualShaderEditor::_mode_selected(int p_id) {
}
} else if (mode & MODE_FLAGS_SKY) {
offset = 8;
+ } else if (mode & MODE_FLAGS_FOG) {
+ offset = 9;
}
visual_shader->set_shader_type(VisualShader::Type(p_id + offset));
_update_options_menu();
_update_graph();
+
+ graph->grab_focus();
}
void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) {
@@ -3730,8 +3756,11 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
case NodeMenuOptions::ADD:
_show_members_dialog(true);
break;
+ case NodeMenuOptions::CUT:
+ _copy_nodes(true);
+ break;
case NodeMenuOptions::COPY:
- _copy_nodes();
+ _copy_nodes(false);
break;
case NodeMenuOptions::PASTE:
_paste_nodes(true, menu_point);
@@ -3742,6 +3771,9 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
case NodeMenuOptions::DUPLICATE:
_duplicate_nodes();
break;
+ case NodeMenuOptions::CLEAR_COPY_BUFFER:
+ _clear_copy_buffer();
+ break;
case NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS:
_convert_constants_to_uniforms(false);
break;
@@ -3956,7 +3988,7 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
ClassDB::bind_method("_uniform_select_item", &VisualShaderEditor::_uniform_select_item);
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
- ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer);
+ ClassDB::bind_method("_clear_copy_buffer", &VisualShaderEditor::_clear_copy_buffer);
ClassDB::bind_method("_update_uniforms", &VisualShaderEditor::_update_uniforms);
ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);
ClassDB::bind_method("_nodes_dragged", &VisualShaderEditor::_nodes_dragged);
@@ -4010,7 +4042,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect("node_selected", callable_mp(this, &VisualShaderEditor::_node_selected));
graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_changed));
graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes));
- graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes));
+ graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes), varray(false));
graph->connect("paste_nodes_request", callable_mp(this, &VisualShaderEditor::_paste_nodes), varray(false, Point2()));
graph->connect("delete_nodes_request", callable_mp(this, &VisualShaderEditor::_delete_nodes_request));
graph->connect("gui_input", callable_mp(this, &VisualShaderEditor::_graph_gui_input));
@@ -4065,6 +4097,11 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type_sky->select(0);
edit_type_sky->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
+ edit_type_fog = memnew(OptionButton);
+ edit_type_fog->add_item(TTR("Fog"));
+ edit_type_fog->select(0);
+ edit_type_fog->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
+
edit_type = edit_type_standard;
graph->get_zoom_hbox()->add_child(custom_mode_box);
@@ -4075,6 +4112,8 @@ VisualShaderEditor::VisualShaderEditor() {
graph->get_zoom_hbox()->move_child(edit_type_particles, 0);
graph->get_zoom_hbox()->add_child(edit_type_sky);
graph->get_zoom_hbox()->move_child(edit_type_sky, 0);
+ graph->get_zoom_hbox()->add_child(edit_type_fog);
+ graph->get_zoom_hbox()->move_child(edit_type_fog, 0);
add_node = memnew(Button);
add_node->set_flat(true);
@@ -4129,10 +4168,12 @@ VisualShaderEditor::VisualShaderEditor() {
add_child(popup_menu);
popup_menu->add_item(TTR("Add Node"), NodeMenuOptions::ADD);
popup_menu->add_separator();
+ popup_menu->add_item(TTR("Cut"), NodeMenuOptions::CUT);
popup_menu->add_item(TTR("Copy"), NodeMenuOptions::COPY);
popup_menu->add_item(TTR("Paste"), NodeMenuOptions::PASTE);
popup_menu->add_item(TTR("Delete"), NodeMenuOptions::DELETE);
popup_menu->add_item(TTR("Duplicate"), NodeMenuOptions::DUPLICATE);
+ popup_menu->add_item(TTR("Clear Copy Buffer"), NodeMenuOptions::CLEAR_COPY_BUFFER);
popup_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed));
///////////////////////////////////////
@@ -4343,6 +4384,7 @@ VisualShaderEditor::VisualShaderEditor() {
const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.");
const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.");
const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.");
+ const String input_param_for_fog_shader_mode = TTR("'%s' input parameter for fog shader mode.");
const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.");
const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.");
const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode.");
@@ -4462,6 +4504,16 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ // FOG INPUTS
+
+ add_options.push_back(AddOption("WorldPosition", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position"), "world_position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("ObjectPosition", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "object_position"), "object_position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("UVW", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw"), "uvw", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("Extents", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "extents"), "extents", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("Transform", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("SDF", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "sdf"), "sdf", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("Time", "Input", "Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+
// PARTICLES INPUTS
add_options.push_back(AddOption("CollisionDepth", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth"), "collision_depth", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 5788959a77..c4a392469b 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -111,7 +111,6 @@ public:
void disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
void show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id);
void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position);
- void set_node_size(VisualShader::Type p_type, int p_id, const Vector2 &p_size);
void refresh_node_ports(VisualShader::Type p_type, int p_node);
void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value);
void update_uniform_refs();
@@ -145,6 +144,7 @@ class VisualShaderEditor : public VBoxContainer {
OptionButton *edit_type_standard;
OptionButton *edit_type_particles;
OptionButton *edit_type_sky;
+ OptionButton *edit_type_fog;
CheckBox *custom_mode_box;
bool custom_mode_enabled = false;
@@ -180,7 +180,8 @@ class VisualShaderEditor : public VBoxContainer {
enum ShaderModeFlags {
MODE_FLAGS_SPATIAL_CANVASITEM = 1,
MODE_FLAGS_SKY = 2,
- MODE_FLAGS_PARTICLES = 4
+ MODE_FLAGS_PARTICLES = 4,
+ MODE_FLAGS_FOG = 8,
};
int mode = MODE_FLAGS_SPATIAL_CANVASITEM;
@@ -203,6 +204,10 @@ class VisualShaderEditor : public VBoxContainer {
TYPE_FLAGS_SKY = 1,
};
+ enum FogTypeFlags {
+ TYPE_FLAGS_FOG = 1,
+ };
+
enum ToolsMenuOptions {
EXPAND_ALL,
COLLAPSE_ALL
@@ -211,10 +216,12 @@ class VisualShaderEditor : public VBoxContainer {
enum NodeMenuOptions {
ADD,
SEPARATOR, // ignore
+ CUT,
COPY,
PASTE,
DELETE,
DUPLICATE,
+ CLEAR_COPY_BUFFER,
SEPARATOR2, // ignore
FLOAT_CONSTANTS,
CONVERT_CONSTANTS_TO_UNIFORMS,
@@ -374,19 +381,27 @@ class VisualShaderEditor : public VBoxContainer {
void _port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output);
- void _dup_copy_nodes(int p_type, List<int> &r_nodes, Set<int> &r_excluded);
- void _dup_update_excluded(int p_type, Set<int> &r_excluded);
- void _dup_paste_nodes(int p_type, int p_pasted_type, List<int> &r_nodes, Set<int> &r_excluded, const Vector2 &p_offset, bool p_select);
+ struct CopyItem {
+ int id;
+ Ref<VisualShaderNode> node;
+ Vector2 position;
+ Vector2 size;
+ String group_inputs;
+ String group_outputs;
+ String expression;
+ };
+
+ void _dup_copy_nodes(int p_type, List<CopyItem> &r_nodes, List<VisualShader::Connection> &r_connections);
+ void _dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate);
void _duplicate_nodes();
Vector2 selection_center;
- int copy_type; // shader type
- List<int> copy_nodes_buffer;
- Set<int> copy_nodes_excluded_buffer;
+ List<CopyItem> copy_items_buffer;
+ List<VisualShader::Connection> copy_connections_buffer;
- void _clear_buffer();
- void _copy_nodes();
+ void _clear_copy_buffer();
+ void _copy_nodes(bool p_cut);
void _paste_nodes(bool p_use_custom_position = false, const Vector2 &p_custom_position = Vector2());
Vector<Ref<VisualShaderNodePlugin>> plugins;
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index e8fd3070c2..c7ab91a49b 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -475,6 +475,13 @@ private:
}
ProjectSettings::CustomMap initial_settings;
initial_settings["rendering/vulkan/rendering/back_end"] = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name"));
+ if (rasterizer_button_group->get_pressed_button()->get_meta("driver_name") == "Vulkan") {
+ initial_settings["rendering/driver/driver_name"] = "Vulkan";
+ } else {
+ initial_settings["rendering/driver/driver_name"] = "OpenGL3";
+ initial_settings["rendering/textures/vram_compression/import_etc2"] = false;
+ initial_settings["rendering/textures/vram_compression/import_etc"] = true;
+ }
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
initial_settings["application/config/icon"] = "res://icon.png";
initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
@@ -1297,8 +1304,7 @@ void ProjectList::update_dock_menu() {
void ProjectList::_global_menu_new_window(const Variant &p_tag) {
List<String> args;
args.push_back("-p");
- String exec = OS::get_singleton()->get_executable_path();
- OS::get_singleton()->create_process(exec, args);
+ OS::get_singleton()->create_instance(args);
}
void ProjectList::_global_menu_open_project(const Variant &p_tag) {
@@ -1308,8 +1314,7 @@ void ProjectList::_global_menu_open_project(const Variant &p_tag) {
String conf = _projects[idx].path.plus_file("project.godot");
List<String> args;
args.push_back(conf);
- String exec = OS::get_singleton()->get_executable_path();
- OS::get_singleton()->create_process(exec, args);
+ OS::get_singleton()->create_instance(args);
}
}
@@ -2055,8 +2060,7 @@ void ProjectManager::_open_selected_projects() {
args.push_back("--single-window");
}
- String exec = OS::get_singleton()->get_executable_path();
- Error err = OS::get_singleton()->create_process(exec, args);
+ Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
}
@@ -2141,8 +2145,7 @@ void ProjectManager::_run_project_confirm() {
args.push_back("--disable-crash-handler");
}
- String exec = OS::get_singleton()->get_executable_path();
- Error err = OS::get_singleton()->create_process(exec, args);
+ Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
}
}
@@ -2271,8 +2274,7 @@ void ProjectManager::_language_selected(int p_id) {
void ProjectManager::_restart_confirm() {
List<String> args = OS::get_singleton()->get_cmdline_args();
- String exec = OS::get_singleton()->get_executable_path();
- Error err = OS::get_singleton()->create_process(exec, args);
+ Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
_dim_window();
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 6ea9b9dfae..db560af657 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -407,11 +407,11 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
return false;
} else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
- hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
+ hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
+ hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
+ hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
+ hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
+ hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
String basename;
switch (hint) {
case PROPERTY_HINT_LAYERS_2D_RENDER:
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index a5e1b0eab8..2792c193d9 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -626,7 +626,7 @@ void RenameDialog::reset() {
bool RenameDialog::_is_main_field(LineEdit *line_edit) {
return line_edit &&
- (line_edit == lne_search || line_edit == lne_replace || line_edit == lne_prefix || line_edit == lne_suffix);
+ (line_edit == lne_search || line_edit == lne_replace || line_edit == lne_prefix || line_edit == lne_suffix);
}
void RenameDialog::_insert_text(String text) {
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index 6bbefb3bb2..8b02544156 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -168,6 +168,11 @@ void ShaderCreateDialog::_create_new() {
code += "\t// Place sky code here.\n";
code += "}\n";
break;
+ case Shader::MODE_FOG:
+ code += "void fog() {\n";
+ code += "\t// Place fog code here.\n";
+ code += "}\n";
+ break;
}
}
text_shader->set_code(code.as_string());