summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/debugger/editor_debugger_node.cpp72
-rw-r--r--editor/debugger/editor_debugger_node.h1
-rw-r--r--editor/debugger/script_editor_debugger.cpp2
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_properties.cpp5
-rw-r--r--editor/editor_properties.h2
-rw-r--r--editor/editor_property_name_processor.cpp1
-rw-r--r--editor/icons/TerrainConnect.svg1
-rw-r--r--editor/icons/TerrainPath.svg1
-rw-r--r--editor/import/dynamic_font_import_settings.cpp9
-rw-r--r--editor/import/resource_importer_dynamic_font.cpp7
-rw-r--r--editor/import/resource_importer_scene.cpp38
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp21
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp165
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp295
-rw-r--r--editor/plugins/tiles/tile_map_editor.h10
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp3
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp7
18 files changed, 411 insertions, 233 deletions
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index bc28b11a71..e13af59d69 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -103,6 +103,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated), varray(id));
node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated), varray(id));
node->connect("remote_object_requested", callable_mp(this, &EditorDebuggerNode::_remote_object_requested), varray(id));
+ node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors));
if (tabs->get_tab_count() > 0) {
get_debugger(0)->clear_style();
@@ -267,40 +268,7 @@ void EditorDebuggerNode::_notification(int p_what) {
}
server->poll();
- // Errors and warnings
- int error_count = 0;
- int warning_count = 0;
- _for_all(tabs, [&](ScriptEditorDebugger *dbg) {
- error_count += dbg->get_error_count();
- warning_count += dbg->get_warning_count();
- });
-
- if (error_count != last_error_count || warning_count != last_warning_count) {
- _for_all(tabs, [&](ScriptEditorDebugger *dbg) {
- dbg->update_tabs();
- });
-
- 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;
- last_warning_count = warning_count;
- }
+ _update_errors();
// Remote scene tree update
remote_scene_tree_timeout -= get_process_delta_time();
@@ -361,6 +329,42 @@ void EditorDebuggerNode::_notification(int p_what) {
}
}
+void EditorDebuggerNode::_update_errors() {
+ int error_count = 0;
+ int warning_count = 0;
+ _for_all(tabs, [&](ScriptEditorDebugger *dbg) {
+ error_count += dbg->get_error_count();
+ warning_count += dbg->get_warning_count();
+ });
+
+ if (error_count != last_error_count || warning_count != last_warning_count) {
+ _for_all(tabs, [&](ScriptEditorDebugger *dbg) {
+ dbg->update_tabs();
+ });
+
+ 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;
+ last_warning_count = warning_count;
+ }
+}
+
void EditorDebuggerNode::_debugger_stopped(int p_id) {
ScriptEditorDebugger *dbg = get_debugger(p_id);
ERR_FAIL_COND(!dbg);
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index 87457fc09a..8dc53690eb 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -116,6 +116,7 @@ private:
ScriptEditorDebugger *_add_debugger();
EditorDebuggerRemoteObject *get_inspected_remote_object();
+ void _update_errors();
friend class DebuggerEditorPlugin;
friend class DebugAdapterParser;
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 9184846408..05409dbeeb 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -1465,6 +1465,7 @@ void ScriptEditorDebugger::_clear_errors_list() {
error_tree->clear();
error_count = 0;
warning_count = 0;
+ emit_signal(SNAME("errors_cleared"));
update_tabs();
expand_all_button->set_disabled(true);
@@ -1626,6 +1627,7 @@ void ScriptEditorDebugger::_bind_methods() {
ADD_SIGNAL(MethodInfo("debug_data", PropertyInfo(Variant::STRING, "msg"), PropertyInfo(Variant::ARRAY, "data")));
ADD_SIGNAL(MethodInfo("set_breakpoint", PropertyInfo("script"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled")));
ADD_SIGNAL(MethodInfo("clear_breakpoints"));
+ ADD_SIGNAL(MethodInfo("errors_cleared"));
}
void ScriptEditorDebugger::add_debugger_plugin(const Ref<Script> &p_script) {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 61f8ab1936..e0a5cab167 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4863,7 +4863,7 @@ bool EditorNode::has_scenes_in_session() {
bool EditorNode::ensure_main_scene(bool p_from_native) {
pick_main_scene->set_meta("from_native", p_from_native); // Whether from play button or native run.
- String main_scene = GLOBAL_DEF("application/run/main_scene", "");
+ String main_scene = GLOBAL_DEF_BASIC("application/run/main_scene", "");
if (main_scene.is_empty()) {
current_menu_option = -1;
@@ -4929,7 +4929,7 @@ bool EditorNode::is_run_playing() const {
String EditorNode::get_run_playing_scene() const {
String run_filename = editor_run.get_running_scene();
if (run_filename.is_empty() && is_run_playing()) {
- run_filename = GLOBAL_DEF("application/run/main_scene", ""); // Must be the main scene then.
+ run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", ""); // Must be the main scene then.
}
return run_filename;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 521f237fb1..ddf1974070 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1259,12 +1259,13 @@ void EditorPropertyInteger::update_property() {
void EditorPropertyInteger::_bind_methods() {
}
-void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser) {
+void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) {
spin->set_min(p_min);
spin->set_max(p_max);
spin->set_step(p_step);
spin->set_allow_greater(p_allow_greater);
spin->set_allow_lesser(p_allow_lesser);
+ spin->set_suffix(p_suffix);
}
EditorPropertyInteger::EditorPropertyInteger() {
@@ -3492,7 +3493,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
- editor->setup(hint.min, hint.max, hint.step, hint.greater, hint.lesser);
+ editor->setup(hint.min, hint.max, hint.step, hint.greater, hint.lesser, hint.suffix);
return editor;
}
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index a3990db678..6513eb0390 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -368,7 +368,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser);
+ void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String());
EditorPropertyInteger();
};
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 1e7638bf72..397afc0653 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -213,6 +213,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["stdout"] = "stdout";
capitalize_string_remaps["sv"] = "SV";
capitalize_string_remaps["svg"] = "SVG";
+ capitalize_string_remaps["taa"] = "TAA";
capitalize_string_remaps["tcp"] = "TCP";
capitalize_string_remaps["ui"] = "UI";
capitalize_string_remaps["url"] = "URL";
diff --git a/editor/icons/TerrainConnect.svg b/editor/icons/TerrainConnect.svg
new file mode 100644
index 0000000000..3b6b8fd5a2
--- /dev/null
+++ b/editor/icons/TerrainConnect.svg
@@ -0,0 +1 @@
+<svg height="32" viewBox="0 0 16 16" width="32" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><circle cx="8" cy="8" r="2.000028" stroke-width="1.09711"/><g stroke-width=".5" transform="translate(0 -1036.4)"><path d="m7 1039.9h-1l2-2.5 2 2.5h-1v2h-2z"/><path d="m3.5606601 1041.3748-.7071068.707-.3535533-3.1818 3.1819804.3535-.7071067.7071.7071067.7071-1.4142135 1.4142z"/><path d="m11.0252 1039.9606-.707-.7071 3.1818-.3535-.3535 3.1819-.7071-.7071-.7071.7071-1.4142-1.4142z"/><path d="m12.43934 1047.4252.707107-.707.353553 3.1818-3.18198-.3535.707106-.7071-.707106-.7071 1.414214-1.4142z"/><path d="m4.9748005 1048.8394.707.7071-3.1818.3535.3535-3.1819.7071.7071.7071-.7071 1.4142 1.4142z"/><path d="m12.5 1043.4v-1l2.5 2-2.5 2v-1h-2v-2z"/><path d="m9 1048.9h1l-2 2.5-2-2.5h1v-2h2z"/><path d="m3.5 1045.4v1l-2.5-2 2.5-2v1h2v2z"/></g></g></svg>
diff --git a/editor/icons/TerrainPath.svg b/editor/icons/TerrainPath.svg
new file mode 100644
index 0000000000..6352bbd37e
--- /dev/null
+++ b/editor/icons/TerrainPath.svg
@@ -0,0 +1 @@
+<svg height="32" viewBox="0 0 16 16" width="32" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><circle cx="3" cy="1049.4" r="2.000028" stroke-width="1.09711"/><circle cx="13" cy="1039.4" r="2.000028" stroke-width="1.09711"/><path d="m7 1038.4v10h-4v2h4 2v-2-8h4v-2h-4z" stroke-width=".46291"/></g></svg>
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index b361dcd036..5e203a3e39 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -454,7 +454,11 @@ void DynamicFontImportSettings::_add_glyph_range_item(int32_t p_start, int32_t p
void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_property) {
// Update font preview.
- if (p_edited_property == "antialiased") {
+ if (p_edited_property == "face_index") {
+ if (font_preview->get_data_count() > 0) {
+ font_preview->get_data(0)->set_face_index(import_settings_data->get("face_index"));
+ }
+ } else if (p_edited_property == "antialiased") {
if (font_preview->get_data_count() > 0) {
font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased"));
}
@@ -945,6 +949,7 @@ void DynamicFontImportSettings::_notification(int p_what) {
void DynamicFontImportSettings::_re_import() {
HashMap<StringName, Variant> main_settings;
+ main_settings["face_index"] = import_settings_data->get("face_index");
main_settings["antialiased"] = import_settings_data->get("antialiased");
main_settings["generate_mipmaps"] = import_settings_data->get("generate_mipmaps");
main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field");
@@ -1299,6 +1304,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
import_settings_data->notify_property_list_changed();
if (font_preview->get_data_count() > 0) {
+ font_preview->get_data(0)->set_face_index(import_settings_data->get("face_index"));
font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased"));
font_preview->get_data(0)->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field"));
font_preview->get_data(0)->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range"));
@@ -1360,6 +1366,7 @@ DynamicFontImportSettings *DynamicFontImportSettings::get_singleton() {
DynamicFontImportSettings::DynamicFontImportSettings() {
singleton = this;
+ options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "face_index"), 0));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp
index 04f6a0b7af..a92b0fe280 100644
--- a/editor/import/resource_importer_dynamic_font.cpp
+++ b/editor/import/resource_importer_dynamic_font.cpp
@@ -50,7 +50,9 @@ void ResourceImporterDynamicFont::get_recognized_extensions(List<String> *p_exte
if (p_extensions) {
#ifdef MODULE_FREETYPE_ENABLED
p_extensions->push_back("ttf");
+ p_extensions->push_back("ttc");
p_extensions->push_back("otf");
+ p_extensions->push_back("otc");
p_extensions->push_back("woff");
p_extensions->push_back("woff2");
p_extensions->push_back("pfb");
@@ -101,6 +103,8 @@ String ResourceImporterDynamicFont::get_preset_name(int p_idx) const {
void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
bool msdf = p_preset == PRESET_MSDF;
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "face_index"), 0));
+
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false));
@@ -179,6 +183,8 @@ void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) {
Error ResourceImporterDynamicFont::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
print_verbose("Importing dynamic font from: " + p_source_file);
+ int face_index = p_options["face_index"];
+
bool antialiased = p_options["antialiased"];
bool generate_mipmaps = p_options["generate_mipmaps"];
bool msdf = p_options["multichannel_signed_distance_field"];
@@ -200,6 +206,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str
Ref<FontData> font;
font.instantiate();
font->set_data(data);
+ font->set_face_index(face_index);
font->set_antialiased(antialiased);
font->set_generate_mipmaps(generate_mipmaps);
font->set_multichannel_signed_distance_field(msdf);
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 80230bc316..f2975b1d7a 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -658,6 +658,44 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
}
}
}
+ } else if (_teststr(name, "vehicle")) {
+ if (isroot) {
+ return p_node;
+ }
+
+ Node *owner = p_node->get_owner();
+ Node3D *s = Object::cast_to<Node3D>(p_node);
+ VehicleBody3D *bv = memnew(VehicleBody3D);
+ String n = _fixstr(p_node->get_name(), "vehicle");
+ bv->set_name(n);
+ p_node->replace_by(bv);
+ p_node->set_name(n);
+ bv->add_child(p_node);
+ bv->set_owner(owner);
+ p_node->set_owner(owner);
+ bv->set_transform(s->get_transform());
+ s->set_transform(Transform3D());
+
+ p_node = bv;
+ } else if (_teststr(name, "wheel")) {
+ if (isroot) {
+ return p_node;
+ }
+
+ Node *owner = p_node->get_owner();
+ Node3D *s = Object::cast_to<Node3D>(p_node);
+ VehicleWheel3D *bv = memnew(VehicleWheel3D);
+ String n = _fixstr(p_node->get_name(), "wheel");
+ bv->set_name(n);
+ p_node->replace_by(bv);
+ p_node->set_name(n);
+ bv->add_child(p_node);
+ bv->set_owner(owner);
+ p_node->set_owner(owner);
+ bv->set_transform(s->get_transform());
+ s->set_transform(Transform3D());
+
+ p_node = bv;
} else if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
//last attempt, maybe collision inside the mesh data
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index bfe9e202d6..83b0d74dd2 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4089,6 +4089,8 @@ void CanvasItemEditor::_button_tool_select(int p_index) {
void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) {
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
+ AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
+ te->make_insert_queue();
for (const KeyValue<Node *, Object *> &E : selection) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
if (!canvas_item || !canvas_item->is_visible_in_tree()) {
@@ -4103,13 +4105,13 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
if (key_pos && p_location) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing);
+ te->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing);
}
if (key_rot && p_rotation) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(n2d, "rotation", n2d->get_rotation(), p_on_existing);
+ te->insert_node_value_key(n2d, "rotation", n2d->get_rotation(), p_on_existing);
}
if (key_scale && p_scale) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing);
+ te->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing);
}
if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) {
@@ -4135,13 +4137,13 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
if (has_chain && ik_chain.size()) {
for (Node2D *&F : ik_chain) {
if (key_pos) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(F, "position", F->get_position(), p_on_existing);
+ te->insert_node_value_key(F, "position", F->get_position(), p_on_existing);
}
if (key_rot) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(F, "rotation", F->get_rotation(), p_on_existing);
+ te->insert_node_value_key(F, "rotation", F->get_rotation(), p_on_existing);
}
if (key_scale) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(F, "scale", F->get_scale(), p_on_existing);
+ te->insert_node_value_key(F, "scale", F->get_scale(), p_on_existing);
}
}
}
@@ -4151,16 +4153,17 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
Control *ctrl = Object::cast_to<Control>(canvas_item);
if (key_pos) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing);
+ te->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing);
}
if (key_rot) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation(), p_on_existing);
+ te->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation(), p_on_existing);
}
if (key_scale) {
- AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing);
+ te->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing);
}
}
}
+ te->commit_insert_queue();
}
void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index d035c038d3..ec45341970 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -1676,10 +1676,15 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
Vector<Color> color;
color.push_back(Color(1.0, 1.0, 1.0, 0.5));
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
+ p_canvas_item->draw_set_transform_matrix(p_transform * xform);
+ p_canvas_item->draw_polygon(polygon, color);
+ }
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)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
p_canvas_item->draw_set_transform_matrix(p_transform * xform);
p_canvas_item->draw_polygon(polygon, color);
@@ -1806,10 +1811,19 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ for (int j = 0; j < polygon.size(); j++) {
+ polygon.write[j] += position;
+ }
+ if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
+ // Draw terrain.
+ p_canvas_item->draw_polygon(polygon, color);
+ }
+
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)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
for (int j = 0; j < polygon.size(); j++) {
polygon.write[j] += position;
}
@@ -1850,10 +1864,16 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
Vector<Color> color;
color.push_back(Color(1.0, 1.0, 1.0, 0.5));
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
+ p_canvas_item->draw_set_transform_matrix(p_transform * xform);
+ p_canvas_item->draw_polygon(polygon, color);
+ }
+
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)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) {
p_canvas_item->draw_set_transform_matrix(p_transform * xform);
p_canvas_item->draw_polygon(polygon, color);
@@ -1926,10 +1946,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (!drag_modified.has(cell)) {
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
+ dict["terrain"] = tile_data->get_terrain();
Array array;
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -1958,10 +1979,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (!drag_modified.has(cell)) {
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
+ dict["terrain"] = tile_data->get_terrain();
Array array;
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -1970,12 +1992,17 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
// Set the terrains bits.
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set());
+ if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
+ tile_data->set_terrain(terrain);
+ }
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- if (tile_data->is_valid_peering_bit_terrain(bit)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit);
+ if (tile_data->is_valid_terrain_peering_bit(bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(tile_data->get_terrain_set(), bit);
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
- tile_data->set_peering_bit_terrain(bit, terrain);
+ tile_data->set_terrain_peering_bit(bit, terrain);
}
}
}
@@ -2000,12 +2027,17 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
dummy_object->set("terrain_set", terrain_set);
dummy_object->set("terrain", -1);
+
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ dummy_object->set("terrain", tile_data->get_terrain());
+ }
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)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
- dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit));
+ dummy_object->set("terrain", tile_data->get_terrain_peering_bit(bit));
}
}
}
@@ -2044,10 +2076,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
// Save the old terrain_set and terrains bits.
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
+ dict["terrain"] = tile_data->get_terrain();
Array array;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -2085,10 +2118,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
// Save the old terrain_set and terrains bits.
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
+ dict["terrain"] = tile_data->get_terrain();
Array array;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -2097,12 +2131,16 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ tile_data->set_terrain(terrain);
+ }
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)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
- tile_data->set_peering_bit_terrain(bit, terrain);
+ tile_data->set_terrain_peering_bit(bit, terrain);
}
}
}
@@ -2138,10 +2176,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.alternative_tile), tile_data->get_terrain_set());
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.alternative_tile), drag_painted_value);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.alternative_tile), tile_data->get_terrain());
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (tile_data->is_valid_peering_bit_terrain(bit)) {
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_peering_bit_terrain(bit));
+ if (tile_data->is_valid_terrain_peering_bit(bit)) {
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_terrain_peering_bit(bit));
}
}
}
@@ -2154,10 +2193,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), drag_painted_value);
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), dict["terrain_set"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
Array array = dict["terrain_peering_bits"];
for (int i = 0; i < array.size(); i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
+ if (tile_set->is_valid_terrain_peering_bit(dict["terrain_set"], bit)) {
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
}
}
@@ -2172,13 +2212,15 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
for (KeyValue<TileMapCell, Variant> &E : drag_modified) {
Dictionary dict = E.value;
Vector2i coords = E.key.get_atlas_coords();
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), terrain);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
Array array = dict["terrain_peering_bits"];
for (int i = 0; i < array.size(); i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), terrain);
}
- if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
+ if (tile_set->is_valid_terrain_peering_bit(dict["terrain_set"], bit)) {
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
}
}
@@ -2224,20 +2266,30 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Vector2i coords = E.get_atlas_coords();
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
+ Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ for (int j = 0; j < polygon.size(); j++) {
+ polygon.write[j] += position;
+ }
+ if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
+ // Draw terrain.
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.alternative_tile), terrain);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.alternative_tile), tile_data->get_terrain());
+ }
+
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)) {
- Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
-
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
for (int j = 0; j < polygon.size(); j++) {
polygon.write[j] += position;
}
if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) {
// Draw bit.
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), terrain);
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_peering_bit_terrain(bit));
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.alternative_tile), tile_data->get_terrain_peering_bit(bit));
}
}
}
@@ -2267,10 +2319,11 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
if (!drag_modified.has(cell)) {
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
+ dict["terrain"] = tile_data->get_terrain();
Array array;
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -2300,10 +2353,11 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
if (!drag_modified.has(cell)) {
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
+ dict["terrain"] = tile_data->get_terrain();
Array array;
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -2312,12 +2366,18 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
// Set the terrains bits.
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set());
+ if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
+ tile_data->set_terrain(terrain);
+ }
+
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
- if (tile_data->is_valid_peering_bit_terrain(bit)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit);
+ if (tile_data->is_valid_terrain_peering_bit(bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(tile_data->get_terrain_set(), bit);
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
- tile_data->set_peering_bit_terrain(bit, terrain);
+ tile_data->set_terrain_peering_bit(bit, terrain);
}
}
}
@@ -2343,12 +2403,18 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
dummy_object->set("terrain_set", terrain_set);
dummy_object->set("terrain", -1);
+
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ dummy_object->set("terrain", tile_data->get_terrain());
+ }
+
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)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
- dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit));
+ dummy_object->set("terrain", tile_data->get_terrain_peering_bit(bit));
}
}
}
@@ -2380,7 +2446,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
Array array;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -2405,10 +2471,11 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
// Save the old terrain_set and terrains bits.
Dictionary dict;
dict["terrain_set"] = tile_data->get_terrain_set();
+ dict["terrain"] = tile_data->get_terrain();
Array array;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1);
+ array.push_back(tile_data->is_valid_terrain_peering_bit(bit) ? tile_data->get_terrain_peering_bit(bit) : -1);
}
dict["terrain_peering_bits"] = array;
drag_modified[cell] = dict;
@@ -2416,12 +2483,17 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
// Set the terrain bit.
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+
+ Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
+ if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
+ tile_data->set_terrain(terrain);
+ }
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)) {
- Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ polygon = tile_set->get_terrain_peering_bit_polygon(terrain_set, bit);
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
- tile_data->set_peering_bit_terrain(bit, terrain);
+ tile_data->set_terrain_peering_bit(bit, terrain);
}
}
}
@@ -2437,6 +2509,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), dict["terrain_set"]);
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E.key.alternative_tile), drag_painted_value);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
Array array = dict["terrain_peering_bits"];
for (int i = 0; i < array.size(); i++) {
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
@@ -2452,13 +2525,15 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
for (KeyValue<TileMapCell, Variant> &E : drag_modified) {
Dictionary dict = E.value;
Vector2i coords = E.key.get_atlas_coords();
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), terrain);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain", coords.x, coords.y, E.key.alternative_tile), dict["terrain"]);
Array array = dict["terrain_peering_bits"];
for (int i = 0; i < array.size(); i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
+ if (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), terrain);
}
- if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) {
+ if (tile_set->is_valid_terrain_peering_bit(dict["terrain_set"], bit)) {
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E.key.alternative_tile), array[i]);
}
}
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index cd8aca2a8e..535ed3b700 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -2321,7 +2321,7 @@ Vector<TileMapEditorPlugin::TabData> TileMapEditorTerrainsPlugin::get_tabs() con
return tabs;
}
-HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const HashMap<Vector2i, TileSet::TerrainsPattern> &p_to_paint, int p_terrain_set) const {
+HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_path_or_connect(const Vector<Vector2i> &p_to_paint, int p_terrain_set, int p_terrain, bool p_connect) const {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
return HashMap<Vector2i, TileMapCell>();
@@ -2332,105 +2332,87 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrains(const
return HashMap<Vector2i, TileMapCell>();
}
- HashMap<Vector2i, TileMapCell> output;
-
- // Add the constraints from the added tiles.
- RBSet<TileMap::TerrainConstraint> added_tiles_constraints_set;
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
- Vector2i coords = E_to_paint.key;
- TileSet::TerrainsPattern terrains_pattern = E_to_paint.value;
-
- RBSet<TileMap::TerrainConstraint> cell_constraints = tile_map->get_terrain_constraints_from_added_tile(coords, p_terrain_set, terrains_pattern);
- for (const TileMap::TerrainConstraint &E : cell_constraints) {
- added_tiles_constraints_set.insert(E);
- }
- }
-
- // Build the list of potential tiles to replace.
- RBSet<Vector2i> potential_to_replace;
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
- Vector2i coords = E_to_paint.key;
- for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
- if (tile_map->is_existing_neighbor(TileSet::CellNeighbor(i))) {
- Vector2i neighbor = tile_map->get_neighbor_cell(coords, TileSet::CellNeighbor(i));
- if (!p_to_paint.has(neighbor)) {
- potential_to_replace.insert(neighbor);
- }
- }
- }
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output;
+ if (p_connect) {
+ terrain_fill_output = tile_map->terrain_fill_connect(tile_map_layer, p_to_paint, p_terrain_set, p_terrain, false);
+ } else {
+ terrain_fill_output = tile_map->terrain_fill_path(tile_map_layer, p_to_paint, p_terrain_set, p_terrain, false);
}
- // Set of tiles to replace
- RBSet<Vector2i> to_replace;
-
- // Add the central tiles to the one to replace.
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
- to_replace.insert(E_to_paint.key);
+ // Make the painted path a set for faster lookups
+ HashSet<Vector2i> painted_set;
+ for (Vector2i coords : p_to_paint) {
+ painted_set.insert(coords);
}
- // Add the constraints from the surroundings of the modified areas.
- RBSet<TileMap::TerrainConstraint> removed_cells_constraints_set;
- bool to_replace_modified = true;
- while (to_replace_modified) {
- // Get the constraints from the removed cells.
- removed_cells_constraints_set = tile_map->get_terrain_constraints_from_removed_cells_list(tile_map_layer, to_replace, p_terrain_set, false);
-
- // Filter the sources to make sure they are in the potential_to_replace.
- RBMap<TileMap::TerrainConstraint, RBSet<Vector2i>> per_constraint_tiles;
- for (const TileMap::TerrainConstraint &E : removed_cells_constraints_set) {
- HashMap<Vector2i, TileSet::CellNeighbor> sources_of_constraint = E.get_overlapping_coords_and_peering_bits();
- for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_source_tile_of_constraint : sources_of_constraint) {
- if (potential_to_replace.has(E_source_tile_of_constraint.key)) {
- per_constraint_tiles[E].insert(E_source_tile_of_constraint.key);
- }
- }
- }
-
- to_replace_modified = false;
- for (const TileMap::TerrainConstraint &E : added_tiles_constraints_set) {
- TileMap::TerrainConstraint c = E;
- // Check if we have a conflict in constraints.
- if (removed_cells_constraints_set.has(c) && removed_cells_constraints_set.find(c)->get().get_terrain() != c.get_terrain()) {
- // If we do, we search for a neighbor to remove.
- if (per_constraint_tiles.has(c) && !per_constraint_tiles[c].is_empty()) {
- // Remove it.
- Vector2i to_add_to_remove = per_constraint_tiles[c].front()->get();
- potential_to_replace.erase(to_add_to_remove);
- to_replace.insert(to_add_to_remove);
- to_replace_modified = true;
- for (KeyValue<TileMap::TerrainConstraint, RBSet<Vector2i>> &E_source_tiles_of_constraint : per_constraint_tiles) {
- E_source_tiles_of_constraint.value.erase(to_add_to_remove);
+ HashMap<Vector2i, TileMapCell> output;
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
+ if (painted_set.has(E.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ bool keep_old = false;
+ TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrains_pattern() == E.value) {
+ keep_old = true;
}
- break;
}
}
+ if (!keep_old) {
+ output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ }
}
}
+ return output;
+}
- // Combine all constraints together.
- RBSet<TileMap::TerrainConstraint> constraints = removed_cells_constraints_set;
- for (const TileMap::TerrainConstraint &E : added_tiles_constraints_set) {
- constraints.insert(E);
+HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_pattern(const Vector<Vector2i> &p_to_paint, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return HashMap<Vector2i, TileMapCell>();
}
- // Remove the central tiles from the ones to replace.
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E_to_paint : p_to_paint) {
- to_replace.erase(E_to_paint.key);
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (!tile_set.is_valid()) {
+ return HashMap<Vector2i, TileMapCell>();
}
- // Run WFC to fill the holes with the constraints.
- HashMap<Vector2i, TileSet::TerrainsPattern> wfc_output = tile_map->terrain_wave_function_collapse(to_replace, p_terrain_set, constraints);
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = tile_map->terrain_fill_pattern(tile_map_layer, p_to_paint, p_terrain_set, p_terrains_pattern, false);
- // 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_terrains_pattern(p_terrain_set, E_to_paint.value);
+ // Make the painted path a set for faster lookups
+ HashSet<Vector2i> painted_set;
+ for (Vector2i coords : p_to_paint) {
+ painted_set.insert(coords);
}
- // 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_terrains_pattern(p_terrain_set, E.value);
+ HashMap<Vector2i, TileMapCell> output;
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
+ if (painted_set.has(E.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && !(tile_data->get_terrains_pattern() == E.value)) {
+ output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ }
+ }
+ }
+ }
}
-
return output;
}
@@ -2445,19 +2427,21 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_line(Vector2i
return HashMap<Vector2i, TileMapCell>();
}
- TileSet::TerrainsPattern terrains_pattern;
- if (p_erase) {
- terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
- } else {
- terrains_pattern = selected_terrains_pattern;
- }
+ if (selected_type == SELECTED_TYPE_CONNECT) {
+ return _draw_terrain_path_or_connect(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, true);
+ } else if (selected_type == SELECTED_TYPE_PATH) {
+ return _draw_terrain_path_or_connect(TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell), selected_terrain_set, selected_terrain, false);
+ } else { // SELECTED_TYPE_PATTERN
+ 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);
- HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
- for (int i = 0; i < line.size(); i++) {
- to_draw[line[i]] = terrains_pattern;
+ Vector<Vector2i> line = TileMapEditor::get_line(tile_map, p_start_cell, p_end_cell);
+ return _draw_terrain_pattern(line, selected_terrain_set, terrains_pattern);
}
- return _draw_terrains(to_draw, selected_terrain_set);
}
HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase) {
@@ -2471,25 +2455,29 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_rect(Vector2i
return HashMap<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();
- HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
+ Vector<Vector2i> 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;
+ to_draw.append(Vector2i(x, y));
}
}
- return _draw_terrains(to_draw, selected_terrain_set);
+
+ if (selected_type == SELECTED_TYPE_CONNECT || selected_type == SELECTED_TYPE_PATH) {
+ return _draw_terrain_path_or_connect(to_draw, selected_terrain_set, selected_terrain, true);
+ } else { // SELECTED_TYPE_PATTERN
+ TileSet::TerrainsPattern terrains_pattern;
+ if (p_erase) {
+ terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ } else {
+ terrains_pattern = selected_terrains_pattern;
+ }
+ return _draw_terrain_pattern(to_draw, selected_terrain_set, terrains_pattern);
+ }
}
RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous) {
@@ -2614,20 +2602,23 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_bucket_fill(Ve
return HashMap<Vector2i, TileMapCell>();
}
- TileSet::TerrainsPattern terrains_pattern;
- if (p_erase) {
- terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
- } else {
- terrains_pattern = selected_terrains_pattern;
- }
-
RBSet<Vector2i> cells_to_draw = _get_cells_for_bucket_fill(p_coords, p_contiguous);
- HashMap<Vector2i, TileSet::TerrainsPattern> to_draw;
- for (const Vector2i &coords : cells_to_draw) {
- to_draw[coords] = terrains_pattern;
+ Vector<Vector2i> cells_to_draw_as_vector;
+ for (Vector2i cell : cells_to_draw) {
+ cells_to_draw_as_vector.append(cell);
}
- return _draw_terrains(to_draw, selected_terrain_set);
+ if (selected_type == SELECTED_TYPE_CONNECT || selected_type == SELECTED_TYPE_PATH) {
+ return _draw_terrain_path_or_connect(cells_to_draw_as_vector, selected_terrain_set, selected_terrain, true);
+ } else { // SELECTED_TYPE_PATTERN
+ TileSet::TerrainsPattern terrains_pattern;
+ if (p_erase) {
+ terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ } else {
+ terrains_pattern = selected_terrains_pattern;
+ }
+ return _draw_terrain_pattern(cells_to_draw_as_vector, selected_terrain_set, terrains_pattern);
+ }
}
void TileMapEditorTerrainsPlugin::_stop_dragging() {
@@ -2696,11 +2687,13 @@ 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(*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;
+ if (int(metadata_dict["type"]) == SELECTED_TYPE_PATTERN) {
+ TileSet::TerrainsPattern in_meta_terrains_pattern(*tile_set, new_terrain_set);
+ in_meta_terrains_pattern.from_array(metadata_dict["terrains_pattern"]);
+ if (in_meta_terrains_pattern == terrains_pattern) {
+ terrains_tile_list->select(i);
+ break;
+ }
}
}
} else {
@@ -2773,22 +2766,33 @@ void TileMapEditorTerrainsPlugin::_update_selection() {
}
// Get the selected terrain.
- selected_terrains_pattern = TileSet::TerrainsPattern();
selected_terrain_set = -1;
+ selected_terrains_pattern = TileSet::TerrainsPattern();
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_terrain = metadata_dict["terrain_id"];
- // Selected tile
+ // Selected mode/terrain pattern
if (erase_button->is_pressed()) {
+ selected_type = SELECTED_TYPE_PATTERN;
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"]);
+ if (int(metadata_dict["type"]) == SELECTED_TYPE_CONNECT) {
+ selected_type = SELECTED_TYPE_CONNECT;
+ } else if (int(metadata_dict["type"]) == SELECTED_TYPE_PATH) {
+ selected_type = SELECTED_TYPE_PATH;
+ } else if (int(metadata_dict["type"]) == SELECTED_TYPE_PATTERN) {
+ selected_type = SELECTED_TYPE_PATTERN;
+ selected_terrains_pattern = TileSet::TerrainsPattern(*tile_set, selected_terrain_set);
+ selected_terrains_pattern.from_array(metadata_dict["terrains_pattern"]);
+ } else {
+ ERR_FAIL();
+ }
}
}
}
@@ -2865,7 +2869,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
} else {
// Paint otherwise.
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()) {
+ if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
@@ -2880,21 +2884,21 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
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()) {
+ if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !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()) {
+ if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !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()) {
+ if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
drag_type = DRAG_TYPE_BUCKET;
@@ -3105,11 +3109,18 @@ void TileMapEditorTerrainsPlugin::_update_terrains_cache() {
cell.alternative_tile = alternative_id;
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
+
+ // Terrain center bit
+ int terrain = terrains_pattern.get_terrain();
+ if (terrain >= 0 && terrain < (int)per_terrain_terrains_patterns[terrain_set].size()) {
+ per_terrain_terrains_patterns[terrain_set][terrain].insert(terrains_pattern);
+ }
+
// Terrain bits.
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 (tile_set->is_valid_terrain_peering_bit(terrain_set, bit)) {
+ terrain = terrains_pattern.get_terrain_peering_bit(bit);
if (terrain >= 0 && terrain < (int)per_terrain_terrains_patterns[terrain_set].size()) {
per_terrain_terrains_patterns[terrain_set][terrain].insert(terrains_pattern);
}
@@ -3191,6 +3202,19 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
ERR_FAIL_INDEX(selected_terrain_set, tile_set->get_terrain_sets_count());
ERR_FAIL_INDEX(selected_terrain_id, tile_set->get_terrains_count(selected_terrain_set));
+ // Add the two first generic modes
+ int item_index = terrains_tile_list->add_icon_item(main_vbox_container->get_theme_icon(SNAME("TerrainConnect"), SNAME("EditorIcons")));
+ terrains_tile_list->set_item_tooltip(item_index, TTR("Connect mode: paints a terrain, then connects it with the surrounding tiles with the same terrain."));
+ Dictionary list_metadata_dict;
+ list_metadata_dict["type"] = SELECTED_TYPE_CONNECT;
+ terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
+
+ item_index = terrains_tile_list->add_icon_item(main_vbox_container->get_theme_icon(SNAME("TerrainPath"), SNAME("EditorIcons")));
+ terrains_tile_list->set_item_tooltip(item_index, TTR("Path mode: paints a terrain, thens connects it to the previous tile painted withing the same stroke."));
+ list_metadata_dict = Dictionary();
+ list_metadata_dict["type"] = SELECTED_TYPE_PATH;
+ terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
+
// Sort the items in a map by the number of corresponding terrains.
RBMap<int, RBSet<TileSet::TerrainsPattern>> sorted;
@@ -3200,7 +3224,7 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
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_terrain(bit) == selected_terrain_id) {
+ if (tile_set->is_valid_terrain_peering_bit(selected_terrain_set, bit) && E.get_terrain_peering_bit(bit) == selected_terrain_id) {
count++;
}
}
@@ -3241,12 +3265,13 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
}
// Create the ItemList's item.
- int item_index = terrains_tile_list->add_item("");
+ item_index = terrains_tile_list->add_item("");
terrains_tile_list->set_item_icon(item_index, icon);
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.get_terrains_as_array();
+ list_metadata_dict = Dictionary();
+ list_metadata_dict["type"] = SELECTED_TYPE_PATTERN;
+ list_metadata_dict["terrains_pattern"] = terrains_pattern.as_array();
terrains_tile_list->set_item_metadata(item_index, list_metadata_dict);
}
}
@@ -3264,6 +3289,8 @@ void TileMapEditorTerrainsPlugin::_update_theme() {
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")));
+
+ _update_tiles_list();
}
void TileMapEditorTerrainsPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
@@ -3303,7 +3330,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
terrains_tile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
terrains_tile_list->set_max_columns(0);
terrains_tile_list->set_same_column_width(true);
- terrains_tile_list->set_fixed_icon_size(Size2(30, 30) * EDSCALE);
+ terrains_tile_list->set_fixed_icon_size(Size2(32, 32) * EDSCALE);
terrains_tile_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
tilemap_tab_terrains->add_child(terrains_tile_list);
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index 7158ebff59..4612bd5fa8 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -268,14 +268,22 @@ private:
HashMap<Vector2i, TileMapCell> drag_modified;
// Painting
- HashMap<Vector2i, TileMapCell> _draw_terrains(const HashMap<Vector2i, TileSet::TerrainsPattern> &p_to_paint, int p_terrain_set) const;
+ HashMap<Vector2i, TileMapCell> _draw_terrain_path_or_connect(const Vector<Vector2i> &p_to_paint, int p_terrain_set, int p_terrain, bool p_connect) const;
+ HashMap<Vector2i, TileMapCell> _draw_terrain_pattern(const Vector<Vector2i> &p_to_paint, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
HashMap<Vector2i, TileMapCell> _draw_line(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
HashMap<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
RBSet<Vector2i> _get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous);
HashMap<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase);
void _stop_dragging();
+ enum SelectedType {
+ SELECTED_TYPE_CONNECT = 0,
+ SELECTED_TYPE_PATH,
+ SELECTED_TYPE_PATTERN,
+ };
+ SelectedType selected_type;
int selected_terrain_set = -1;
+ int selected_terrain = -1;
TileSet::TerrainsPattern selected_terrains_pattern;
void _update_selection();
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index b87aedcf60..66459d3ef9 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -2071,9 +2071,10 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
}
} else if (p_property == "terrain_set") {
int current_terrain_set = tile_data_proxy->get("terrain_set");
+ ADD_UNDO(tile_data_proxy, "terrain");
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (tile_set->is_valid_peering_bit_terrain(current_terrain_set, bit)) {
+ if (tile_set->is_valid_terrain_peering_bit(current_terrain_set, bit)) {
ADD_UNDO(tile_data_proxy, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
}
}
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index fb4a563992..de373e121b 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -505,7 +505,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
for (int terrain_set_index = begin; terrain_set_index < end; terrain_set_index++) {
for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(l);
- if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ if (tile_data->is_valid_terrain_peering_bit(bit)) {
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l]));
}
}
@@ -513,7 +513,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
} else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
for (int terrain_index = 0; terrain_index < TileSet::CELL_NEIGHBOR_MAX; terrain_index++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(terrain_index);
- if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ if (tile_data->is_valid_terrain_peering_bit(bit)) {
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[terrain_index]));
}
}
@@ -607,9 +607,10 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
if (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") {
ADD_UNDO(tile_data, "terrain_set");
+ ADD_UNDO(tile_data, "terrain");
for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(l);
- if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ if (tile_data->is_valid_terrain_peering_bit(bit)) {
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l]));
}
}