diff options
46 files changed, 904 insertions, 628 deletions
diff --git a/core/project_settings.cpp b/core/project_settings.cpp index b7fd6d7318..427fa77e62 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -453,8 +453,11 @@ Error ProjectSettings::_load_settings_text(const String p_path) { Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) - return ERR_CANT_OPEN; + if (!f) { + // FIXME: Above 'err' error code is ERR_FILE_CANT_OPEN if the file is missing + // This needs to be streamlined if we want decent error reporting + return ERR_FILE_NOT_FOUND; + } VariantParser::StreamFile stream; stream.f = f; @@ -513,6 +516,7 @@ Error ProjectSettings::_load_settings_text_or_binary(const String p_text_path, c return OK; } else if (err_text != ERR_FILE_NOT_FOUND) { // If the text-based file exists but can't be loaded, we want to know it + ERR_PRINTS("Couldn't load file '" + p_text_path + "', error code " + itos(err_text) + "."); return err_text; } diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml index 850a7366bc..ebeb1e0aa0 100644 --- a/doc/classes/ButtonGroup.xml +++ b/doc/classes/ButtonGroup.xml @@ -5,6 +5,7 @@ </brief_description> <description> Group of [Button]. All direct and indirect children buttons become radios. Only one allows being pressed. + [member BaseButton.toggle_mode] should be [code]true[/code]. </description> <tutorials> </tutorials> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index f68f80fa8e..7e8cc1179c 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -280,7 +280,7 @@ </signal> <signal name="item_activated"> <description> - Emitted when an item is activated (double-clicked). + Emitted when an item's label is double-clicked. </description> </signal> <signal name="item_collapsed"> @@ -296,7 +296,7 @@ </signal> <signal name="item_double_clicked"> <description> - Emitted when an item is double clicked. + Emitted when an item's icon is double-clicked. </description> </signal> <signal name="item_edited"> diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 37a2450377..96fa800206 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -993,13 +993,11 @@ void RasterizerCanvasGLES3::_copy_texscreen(const Rect2 &p_rect) { glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //back to front glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); - state.canvas_shader.bind(); //back to canvas - _bind_canvas_texture(state.current_tex, state.current_normal); + // back to canvas, force rebind + state.using_texture_rect = true; + _set_texture_rect_mode(false); - if (state.using_texture_rect) { - state.using_texture_rect = false; - _set_texture_rect_mode(state.using_texture_rect, state.using_ninepatch); - } + _bind_canvas_texture(state.current_tex, state.current_normal); glEnable(GL_BLEND); } diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index f1d7085d54..070c661c8a 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -477,22 +477,22 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener current_func_name = fnode->name; - if (fnode->name == "vertex") { + if (fnode->name == vertex_name) { _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx); - r_gen_code.vertex = function_code["vertex"]; + r_gen_code.vertex = function_code[vertex_name]; } - if (fnode->name == "fragment") { + if (fnode->name == fragment_name) { _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); - r_gen_code.fragment = function_code["fragment"]; + r_gen_code.fragment = function_code[fragment_name]; } - if (fnode->name == "light") { + if (fnode->name == light_name) { _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); - r_gen_code.light = function_code["light"]; + r_gen_code.light = function_code[light_name]; } } @@ -573,7 +573,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener if (current_func_name == vertex_name) { r_gen_code.uses_vertex_time = true; } - if (current_func_name == fragment_name) { + if (current_func_name == fragment_name || current_func_name == light_name) { r_gen_code.uses_fragment_time = true; } } @@ -939,6 +939,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { vertex_name = "vertex"; fragment_name = "fragment"; + light_name = "light"; time_name = "TIME"; List<String> func_list; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index 85e8e02b8e..bf776ee062 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -83,6 +83,7 @@ private: StringName current_func_name; StringName vertex_name; StringName fragment_name; + StringName light_name; StringName time_name; Set<StringName> used_name_defines; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index a2641738f3..c06531d975 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -505,7 +505,7 @@ void ScriptEditor::_show_error_dialog(String p_path) { error_dialog->popup_centered_minsize(); } -void ScriptEditor::_close_tab(int p_idx, bool p_save) { +void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { int selected = p_idx; if (selected < 0 || selected >= tab_container->get_child_count()) @@ -521,7 +521,9 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save) { } // roll back to previous tab - _history_back(); + if (p_history_back) { + _history_back(); + } //remove from history history.resize(history_pos + 1); @@ -579,7 +581,7 @@ void ScriptEditor::_close_docs_tab() { EditorHelp *se = Object::cast_to<EditorHelp>(tab_container->get_child(i)); if (se) { - _close_tab(i); + _close_tab(i, true, false); } } } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index a5531c96b5..bcc604d990 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -252,7 +252,7 @@ class ScriptEditor : public PanelContainer { void _show_error_dialog(String p_path); - void _close_tab(int p_idx, bool p_save = true); + void _close_tab(int p_idx, bool p_save = true, bool p_history_back = true); void _close_current_tab(); void _close_discard_current_tab(const String &p_str); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index e04798d6d6..215d2ca551 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -57,6 +57,8 @@ void TextureRegionEditor::_region_draw() { base_tex = obj_styleBox->get_texture(); else if (atlas_tex.is_valid()) base_tex = atlas_tex->get_atlas(); + else if (tile_set.is_valid() && selected_tile != -1) + base_tex = tile_set->tile_get_texture(selected_tile); if (base_tex.is_null()) return; @@ -281,6 +283,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { r = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) r = atlas_tex->get_region(); + else if (tile_set.is_valid() && selected_tile != -1) + r = tile_set->tile_get_region(selected_tile); rect.expand_to(r.position); rect.expand_to(r.position + r.size); } @@ -297,6 +301,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else if (atlas_tex.is_valid()) { undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect); undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region()); + } else if (tile_set.is_valid() && selected_tile != -1) { + undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, rect); + undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile)); } undo_redo->add_do_method(edit_draw, "update"); undo_redo->add_undo_method(edit_draw, "update"); @@ -319,6 +326,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { rect_prev = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) rect_prev = atlas_tex->get_region(); + else if (tile_set.is_valid() && selected_tile != -1) + rect_prev = tile_set->tile_get_region(selected_tile); for (int i = 0; i < 8; i++) { Vector2 tuv = endpoints[i]; @@ -362,6 +371,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else if (obj_styleBox.is_valid()) { undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect()); undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", rect_prev); + } else if (tile_set.is_valid()) { + undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile)); + undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, rect_prev); } drag_index = -1; } @@ -582,6 +594,8 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) { obj_styleBox->set_region_rect(rect); else if (atlas_tex.is_valid()) atlas_tex->set_region(rect); + else if (tile_set.is_valid() && selected_tile != -1) + tile_set->tile_set_region(selected_tile, rect); } void TextureRegionEditor::_notification(int p_what) { @@ -596,11 +610,12 @@ void TextureRegionEditor::_notification(int p_what) { } void TextureRegionEditor::_node_removed(Object *p_obj) { - if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) { + if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr() || p_obj == tile_set.ptr()) { node_ninepatch = NULL; node_sprite = NULL; obj_styleBox = Ref<StyleBox>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); + tile_set = Ref<TileSet>(NULL); hide(); } } @@ -632,6 +647,8 @@ void TextureRegionEditor::edit(Object *p_obj) { obj_styleBox->remove_change_receptor(this); if (atlas_tex.is_valid()) atlas_tex->remove_change_receptor(this); + if (tile_set.is_valid()) + tile_set->remove_change_receptor(this); if (p_obj) { node_sprite = Object::cast_to<Sprite>(p_obj); node_ninepatch = Object::cast_to<NinePatchRect>(p_obj); @@ -639,6 +656,8 @@ void TextureRegionEditor::edit(Object *p_obj) { obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj)); if (Object::cast_to<AtlasTexture>(p_obj)) atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj)); + if (Object::cast_to<TileSet>(p_obj)) + tile_set = Ref<TileSet>(Object::cast_to<TileSet>(p_obj)); p_obj->add_change_receptor(this); _edit_region(); } else { @@ -646,6 +665,7 @@ void TextureRegionEditor::edit(Object *p_obj) { node_ninepatch = NULL; obj_styleBox = Ref<StyleBoxTexture>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); + tile_set = Ref<TileSet>(NULL); } edit_draw->update(); } @@ -668,6 +688,8 @@ void TextureRegionEditor::_edit_region() { texture = obj_styleBox->get_texture(); else if (atlas_tex.is_valid()) texture = atlas_tex->get_atlas(); + else if (tile_set.is_valid() && selected_tile != -1) + texture = tile_set->tile_get_texture(selected_tile); if (texture.is_null()) { return; @@ -735,6 +757,8 @@ void TextureRegionEditor::_edit_region() { rect = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) rect = atlas_tex->get_region(); + else if (tile_set.is_valid() && selected_tile != -1) + rect = tile_set->tile_get_region(selected_tile); edit_draw->update(); } @@ -753,6 +777,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { node_ninepatch = NULL; obj_styleBox = Ref<StyleBoxTexture>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); + tile_set = Ref<TileSet>(NULL); editor = p_editor; undo_redo = editor->get_undo_redo(); @@ -903,11 +928,11 @@ bool TextureRegionEditorPlugin::handles(Object *p_object) const { void TextureRegionEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - region_button->show(); - if (region_button->is_pressed()) + texture_region_button->show(); + if (texture_region_button->is_pressed()) region_editor->show(); } else { - region_button->hide(); + texture_region_button->hide(); region_editor->edit(NULL); region_editor->hide(); } @@ -961,10 +986,10 @@ TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) { editor = p_node; region_editor = memnew(TextureRegionEditor(p_node)); - region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), region_editor); - region_button->set_tooltip(TTR("Texture Region Editor")); + texture_region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), region_editor); + texture_region_button->set_tooltip(TTR("Texture Region Editor")); region_editor->set_custom_minimum_size(Size2(0, 200)); region_editor->hide(); - region_button->hide(); + texture_region_button->hide(); } diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index cf9396bd5b..1244953a3f 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -38,6 +38,7 @@ #include "scene/gui/nine_patch_rect.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" +#include "scene/resources/tile_set.h" /** @author Mariano Suligoy @@ -55,6 +56,8 @@ class TextureRegionEditor : public Control { }; friend class TextureRegionEditorPlugin; + friend class TileSetEditor; + friend class TileSetEditorPlugin; MenuButton *snap_mode_button; TextureRect *icon_zoom; ToolButton *zoom_in; @@ -88,12 +91,14 @@ class TextureRegionEditor : public Control { Sprite *node_sprite; Ref<StyleBoxTexture> obj_styleBox; Ref<AtlasTexture> atlas_tex; + Ref<TileSet> tile_set; Rect2 rect; Rect2 rect_prev; float prev_margin; int edited_margin; List<Rect2> autoslice_cache; + int selected_tile; bool drag; bool creating; @@ -134,7 +139,7 @@ public: class TextureRegionEditorPlugin : public EditorPlugin { GDCLASS(TextureRegionEditorPlugin, EditorPlugin); - Button *region_button; + Button *texture_region_button; TextureRegionEditor *region_editor; EditorNode *editor; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index a102d99d1c..c97e949403 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -303,7 +303,7 @@ void TileMapEditor::_update_palette() { if (tex.is_valid()) { Rect2 region = tileset->tile_get_region(entries[i].id); - if (tileset->tile_get_is_autotile(entries[i].id)) { + if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE) { int spacing = tileset->autotile_get_spacing(entries[i].id); region.size = tileset->autotile_get_size(entries[i].id); region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id); @@ -506,7 +506,7 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i &p_point, bool p_flip_h Vector2 tile_ofs = node->get_tileset()->tile_get_texture_offset(p_cell); Rect2 r = node->get_tileset()->tile_get_region(p_cell); - if (node->get_tileset()->tile_get_is_autotile(p_cell)) { + if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE) { int spacing = node->get_tileset()->autotile_get_spacing(p_cell); r.size = node->get_tileset()->autotile_get_size(p_cell); r.position += (r.size + Vector2(spacing, spacing)) * node->get_tileset()->autotile_get_icon_coordinate(p_cell); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 2ff8536b4c..71c0d8a782 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -37,6 +37,9 @@ void TileSetEditor::edit(const Ref<TileSet> &p_tileset) { tileset = p_tileset; + tileset->add_change_receptor(this); + + update_tile_list(); } void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { @@ -188,6 +191,7 @@ void TileSetEditor::_name_dialog_confirm(const String &name) { if (tileset->has_tile(id)) { tileset->remove_tile(id); + update_tile_list(); } else { err_dialog->set_text(TTR("Could not find tile:") + " " + name); err_dialog->popup_centered(Size2(300, 60)); @@ -202,8 +206,9 @@ void TileSetEditor::_menu_cbk(int p_option) { switch (p_option) { case MENU_OPTION_ADD_ITEM: { - tileset->create_tile(tileset->get_last_unused_tile_id()); + tileset->tile_set_name(tileset->get_last_unused_tile_id() - 1, itos(tileset->get_last_unused_tile_id() - 1)); + update_tile_list(); } break; case MENU_OPTION_REMOVE_ITEM: { @@ -235,106 +240,75 @@ void TileSetEditor::_bind_methods() { ClassDB::bind_method("_menu_cbk", &TileSetEditor::_menu_cbk); ClassDB::bind_method("_menu_confirm", &TileSetEditor::_menu_confirm); ClassDB::bind_method("_name_dialog_confirm", &TileSetEditor::_name_dialog_confirm); + ClassDB::bind_method("_on_tile_list_selected", &TileSetEditor::_on_tile_list_selected); + ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed); + ClassDB::bind_method("_on_workspace_draw", &TileSetEditor::_on_workspace_draw); + ClassDB::bind_method("_on_workspace_input", &TileSetEditor::_on_workspace_input); + ClassDB::bind_method("_on_tool_clicked", &TileSetEditor::_on_tool_clicked); + ClassDB::bind_method("_on_priority_changed", &TileSetEditor::_on_priority_changed); + ClassDB::bind_method("_on_grid_snap_toggled", &TileSetEditor::_on_grid_snap_toggled); + ClassDB::bind_method("_set_snap_step_x", &TileSetEditor::_set_snap_step_x); + ClassDB::bind_method("_set_snap_step_y", &TileSetEditor::_set_snap_step_y); + ClassDB::bind_method("_set_snap_off_x", &TileSetEditor::_set_snap_off_x); + ClassDB::bind_method("_set_snap_off_y", &TileSetEditor::_set_snap_off_y); + ClassDB::bind_method("_set_snap_sep_x", &TileSetEditor::_set_snap_sep_x); + ClassDB::bind_method("_set_snap_sep_y", &TileSetEditor::_set_snap_sep_y); } -TileSetEditor::TileSetEditor(EditorNode *p_editor) { - - menu = memnew(MenuButton); - CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu); - menu->hide(); - menu->set_text(TTR("Tile Set")); - menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); - menu->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM); - menu->get_popup()->add_separator(); - menu->get_popup()->add_item(TTR("Create from Scene"), MENU_OPTION_CREATE_FROM_SCENE); - menu->get_popup()->add_item(TTR("Merge from Scene"), MENU_OPTION_MERGE_FROM_SCENE); - menu->get_popup()->connect("id_pressed", this, "_menu_cbk"); - editor = p_editor; - cd = memnew(ConfirmationDialog); - add_child(cd); - cd->get_ok()->connect("pressed", this, "_menu_confirm"); - - nd = memnew(EditorNameDialog); - add_child(nd); - nd->set_hide_on_ok(true); - nd->get_line_edit()->set_margin(MARGIN_TOP, 28); - nd->connect("name_confirmed", this, "_name_dialog_confirm"); - - err_dialog = memnew(AcceptDialog); - add_child(err_dialog); - err_dialog->set_title(TTR("Error")); -} - -void TileSetEditorPlugin::edit(Object *p_node) { - - if (Object::cast_to<TileSet>(p_node)) { - tileset_editor->edit(Object::cast_to<TileSet>(p_node)); - tileset_editor->show(); - autotile_editor->edit(p_node); - } else - tileset_editor->hide(); -} - -bool TileSetEditorPlugin::handles(Object *p_node) const { - - return p_node->is_class("TileSet"); -} - -void TileSetEditorPlugin::make_visible(bool p_visible) { - - if (p_visible) { - tileset_editor->show(); - tileset_editor->menu->show(); - autotile_button->show(); - autotile_editor->side_panel->show(); - if (autotile_button->is_pressed()) { - autotile_editor->show(); - } - } else { - tileset_editor->hide(); - tileset_editor->menu->hide(); - autotile_editor->side_panel->hide(); - autotile_editor->hide(); - autotile_button->hide(); +void TileSetEditor::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE) { + tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); + tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons")); + tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons")); + tools[BITMASK_CLEAR]->set_icon(get_icon("Clear", "EditorIcons")); + tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons")); + tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons")); + tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons")); + tools[SHAPE_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); + tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons")); + tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons")); + tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons")); } } -TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) { - - tileset_editor = memnew(TileSetEditor(p_node)); - - add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, tileset_editor); - tileset_editor->set_anchors_and_margins_preset(Control::PRESET_TOP_WIDE); - tileset_editor->set_end(Point2(0, 22)); - tileset_editor->hide(); - - autotile_editor = memnew(AutotileEditor(p_node)); - add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE, autotile_editor->side_panel); - autotile_editor->side_panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); - autotile_editor->side_panel->set_custom_minimum_size(Size2(200, 0)); - autotile_editor->side_panel->hide(); - autotile_button = p_node->add_bottom_panel_item(TTR("Autotiles"), autotile_editor); - autotile_button->hide(); +void TileSetEditor::_changed_callback(Object *p_changed, const char *p_prop) { + if (p_prop == StringName("region")) { + update_tile_list_icon(); + preview->set_region_rect(tileset->tile_get_region(get_current_tile())); + } else if (p_prop == StringName("name")) { + update_tile_list_icon(); + } else if (p_prop == StringName("texture") || p_prop == StringName("tile_mode")) { + _on_tile_list_selected(get_current_tile()); + workspace->update(); + preview->set_texture(tileset->tile_get_texture(get_current_tile())); + preview->set_region_rect(tileset->tile_get_region(get_current_tile())); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + property_editor->show(); + else + property_editor->hide(); + texture_region_editor->_edit_region(); + update_tile_list_icon(); + } else if (p_prop == StringName("autotile")) { + workspace->update(); + } } -AutotileEditor::AutotileEditor(EditorNode *p_editor) { - - editor = p_editor; +void TileSetEditor::initialize_bottom_editor() { //Side Panel side_panel = memnew(Control); - side_panel->set_name("Autotiles"); + side_panel->set_name("Tile Set"); VSplitContainer *split = memnew(VSplitContainer); side_panel->add_child(split); split->set_anchors_and_margins_preset(Control::PRESET_WIDE); - autotile_list = memnew(ItemList); - autotile_list->set_v_size_flags(SIZE_EXPAND_FILL); - autotile_list->set_h_size_flags(SIZE_EXPAND_FILL); - autotile_list->set_custom_minimum_size(Size2(10, 200)); - autotile_list->connect("item_selected", this, "_on_autotile_selected"); - split->add_child(autotile_list); + tile_list = memnew(ItemList); + tile_list->set_v_size_flags(SIZE_EXPAND_FILL); + tile_list->set_h_size_flags(SIZE_EXPAND_FILL); + tile_list->set_custom_minimum_size(Size2(10, 200)); + tile_list->connect("item_selected", this, "_on_tile_list_selected"); + split->add_child(tile_list); property_editor = memnew(PropertyEditor); property_editor->set_v_size_flags(SIZE_EXPAND_FILL); @@ -342,25 +316,29 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { property_editor->set_custom_minimum_size(Size2(10, 70)); split->add_child(property_editor); - helper = memnew(AutotileEditorHelper(this)); + helper = memnew(TileSetEditorHelper(this)); property_editor->call_deferred("edit", helper); + helper->add_change_receptor(this); //Editor + //Bottom Panel + bottom_panel = memnew(Control); + bottom_panel->set_name("Tile Set Bottom Editor"); dragging_point = -1; creating_shape = false; snap_step = Vector2(32, 32); - set_custom_minimum_size(Size2(0, 150)); + bottom_panel->set_custom_minimum_size(Size2(0, 150)); VBoxContainer *main_vb = memnew(VBoxContainer); - add_child(main_vb); + bottom_panel->add_child(main_vb); main_vb->set_anchors_and_margins_preset(Control::PRESET_WIDE); HBoxContainer *tool_hb = memnew(HBoxContainer); Ref<ButtonGroup> g(memnew(ButtonGroup)); - String label[EDITMODE_MAX] = { "Icon", "Bitmask", "Collision", "Occlusion", "Navigation", "Priority" }; + String label[EDITMODE_MAX] = { "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" }; for (int i = 0; i < (int)EDITMODE_MAX; i++) { tool_editmode[i] = memnew(Button); @@ -372,7 +350,8 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", args); tool_hb->add_child(tool_editmode[i]); } - tool_editmode[EDITMODE_ICON]->set_pressed(true); + tool_editmode[EDITMODE_COLLISION]->set_pressed(true); + edit_mode = EDITMODE_COLLISION; main_vb->add_child(tool_hb); main_vb->add_child(memnew(HSeparator)); @@ -386,15 +365,17 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { Ref<ButtonGroup> tg(memnew(ButtonGroup)); + Vector<Variant> p; tools[TOOL_SELECT] = memnew(ToolButton); tool_containers[TOOLBAR_DUMMY]->add_child(tools[TOOL_SELECT]); tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.")); tools[TOOL_SELECT]->set_toggle_mode(true); tools[TOOL_SELECT]->set_button_group(tg); tools[TOOL_SELECT]->set_pressed(true); + p.push_back((int)TOOL_SELECT); + tools[TOOL_SELECT]->connect("pressed", this, "_on_tool_clicked", p); tool_containers[TOOLBAR_DUMMY]->show(); - Vector<Variant> p; tools[BITMASK_COPY] = memnew(ToolButton); p.push_back((int)BITMASK_COPY); tools[BITMASK_COPY]->connect("pressed", this, "_on_tool_clicked", p); @@ -420,7 +401,7 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { p.push_back((int)SHAPE_DELETE); tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", p); tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_DELETE]); - tool_containers[TOOLBAR_SHAPE]->add_child(memnew(VSeparator)); + tool_containers[TOOLBAR_SHAPE]->add_change_receptor(memnew(VSeparator)); tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true); @@ -507,6 +488,8 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { spin_priority->hide(); toolbar->add_child(spin_priority); + tool_containers[TOOLBAR_SHAPE]->show(); + Control *separator = memnew(Control); separator->set_h_size_flags(SIZE_EXPAND_FILL); toolbar->add_child(separator); @@ -548,70 +531,56 @@ AutotileEditor::AutotileEditor(EditorNode *p_editor) { preview->set_region(true); } -AutotileEditor::~AutotileEditor() { - memdelete(helper); -} +TileSetEditor::TileSetEditor(EditorNode *p_editor) { -void AutotileEditor::_bind_methods() { - - ClassDB::bind_method("_on_autotile_selected", &AutotileEditor::_on_autotile_selected); - ClassDB::bind_method("_on_edit_mode_changed", &AutotileEditor::_on_edit_mode_changed); - ClassDB::bind_method("_on_workspace_draw", &AutotileEditor::_on_workspace_draw); - ClassDB::bind_method("_on_workspace_input", &AutotileEditor::_on_workspace_input); - ClassDB::bind_method("_on_tool_clicked", &AutotileEditor::_on_tool_clicked); - ClassDB::bind_method("_on_priority_changed", &AutotileEditor::_on_priority_changed); - ClassDB::bind_method("_on_grid_snap_toggled", &AutotileEditor::_on_grid_snap_toggled); - ClassDB::bind_method("_set_snap_step_x", &AutotileEditor::_set_snap_step_x); - ClassDB::bind_method("_set_snap_step_y", &AutotileEditor::_set_snap_step_y); - ClassDB::bind_method("_set_snap_off_x", &AutotileEditor::_set_snap_off_x); - ClassDB::bind_method("_set_snap_off_y", &AutotileEditor::_set_snap_off_y); - ClassDB::bind_method("_set_snap_sep_x", &AutotileEditor::_set_snap_sep_x); - ClassDB::bind_method("_set_snap_sep_y", &AutotileEditor::_set_snap_sep_y); -} + menu = memnew(MenuButton); + CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu); + menu->hide(); + menu->set_text(TTR("Tile Set")); + menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); + menu->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM); + menu->get_popup()->add_separator(); + menu->get_popup()->add_item(TTR("Create from Scene"), MENU_OPTION_CREATE_FROM_SCENE); + menu->get_popup()->add_item(TTR("Merge from Scene"), MENU_OPTION_MERGE_FROM_SCENE); + menu->get_popup()->connect("id_pressed", this, "_menu_cbk"); + editor = p_editor; + cd = memnew(ConfirmationDialog); + add_child(cd); + cd->get_ok()->connect("pressed", this, "_menu_confirm"); -void AutotileEditor::_notification(int p_what) { + nd = memnew(EditorNameDialog); + add_child(nd); + nd->set_hide_on_ok(true); + nd->get_line_edit()->set_margin(MARGIN_TOP, 28); + nd->connect("name_confirmed", this, "_name_dialog_confirm"); - if (p_what == NOTIFICATION_ENTER_TREE) { - tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); - tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons")); - tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons")); - tools[BITMASK_CLEAR]->set_icon(get_icon("Clear", "EditorIcons")); - tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons")); - tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons")); - tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons")); - tools[SHAPE_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); - tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons")); - tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons")); - tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons")); - } -} + err_dialog = memnew(AcceptDialog); + add_child(err_dialog); + err_dialog->set_title(TTR("Error")); -void AutotileEditor::_changed_callback(Object *p_changed, const char *p_prop) { - if (p_prop == StringName("texture") || p_prop == StringName("is_autotile")) { - edit(tile_set.ptr()); - autotile_list->update(); - workspace->update(); - } + initialize_bottom_editor(); } -void AutotileEditor::_on_autotile_selected(int p_index) { - +void TileSetEditor::_on_tile_list_selected(int p_index) { if (get_current_tile() >= 0) { current_item_index = p_index; - preview->set_texture(tile_set->tile_get_texture(get_current_tile())); - preview->set_region_rect(tile_set->tile_get_region(get_current_tile())); - workspace->set_custom_minimum_size(tile_set->tile_get_region(get_current_tile()).size); + preview->set_texture(tileset->tile_get_texture(get_current_tile())); + preview->set_region_rect(tileset->tile_get_region(get_current_tile())); + workspace->set_custom_minimum_size(tileset->tile_get_region(get_current_tile()).size); + update_workspace_tile_mode(); } else { current_item_index = -1; preview->set_texture(NULL); workspace->set_custom_minimum_size(Size2i()); } + texture_region_editor->selected_tile = get_current_tile(); + texture_region_editor->_edit_region(); + helper->selected_tile = get_current_tile(); helper->_change_notify(""); workspace->update(); } -void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) { - +void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { edit_mode = (EditMode)p_edit_mode; switch (edit_mode) { case EDITMODE_BITMASK: { @@ -631,7 +600,6 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) { tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.")); spin_priority->hide(); - current_shape = PoolVector2Array(); select_coord(edited_shape_coord); } break; default: { @@ -650,17 +618,17 @@ void AutotileEditor::_on_edit_mode_changed(int p_edit_mode) { workspace->update(); } -void AutotileEditor::_on_workspace_draw() { +void TileSetEditor::_on_workspace_draw() { - if (get_current_tile() >= 0 && !tile_set.is_null()) { - int spacing = tile_set->autotile_get_spacing(get_current_tile()); - Vector2 size = tile_set->autotile_get_size(get_current_tile()); - Rect2i region = tile_set->tile_get_region(get_current_tile()); + if (get_current_tile() >= 0 && !tileset.is_null()) { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + Rect2i region = tileset->tile_get_region(get_current_tile()); Color c(0.347214, 0.722656, 0.617063); switch (edit_mode) { case EDITMODE_ICON: { - Vector2 coord = tile_set->autotile_get_icon_coordinate(get_current_tile()); + Vector2 coord = tileset->autotile_get_icon_coordinate(get_current_tile()); draw_highlight_tile(coord); } break; case EDITMODE_BITMASK: { @@ -669,8 +637,8 @@ void AutotileEditor::_on_workspace_draw() { for (float y = 0; y < region.size.y / (spacing + size.y); y++) { Vector2 coord(x, y); Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - uint16_t mask = tile_set->autotile_get_bitmask(get_current_tile(), coord); - if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { + uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); + if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (mask & TileSet::BIND_TOPLEFT) { workspace->draw_rect(Rect2(anchor, size / 2), c); } @@ -683,7 +651,7 @@ void AutotileEditor::_on_workspace_draw() { if (mask & TileSet::BIND_BOTTOMRIGHT) { workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c); } - } else if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { if (mask & TileSet::BIND_TOPLEFT) { workspace->draw_rect(Rect2(anchor, size / 3), c); } @@ -718,19 +686,21 @@ void AutotileEditor::_on_workspace_draw() { case EDITMODE_COLLISION: case EDITMODE_OCCLUSION: case EDITMODE_NAVIGATION: { - Vector2 coord = edited_shape_coord; - draw_highlight_tile(coord); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + Vector2 coord = edited_shape_coord; + draw_highlight_tile(coord); + } draw_polygon_shapes(); draw_grid_snap(); } break; case EDITMODE_PRIORITY: { - spin_priority->set_value(tile_set->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)); - uint16_t mask = tile_set->autotile_get_bitmask(get_current_tile(), edited_shape_coord); + spin_priority->set_value(tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)); + uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord); Vector<Vector2> queue_others; int total = 0; - for (Map<Vector2, uint16_t>::Element *E = tile_set->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) { + for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) { if (E->value() == mask) { - total += tile_set->autotile_get_subtile_priority(get_current_tile(), E->key()); + total += tileset->autotile_get_subtile_priority(get_current_tile(), E->key()); if (E->key() != edited_shape_coord) { queue_others.push_back(E->key()); } @@ -741,53 +711,55 @@ void AutotileEditor::_on_workspace_draw() { } break; } - float j = -size.x; //make sure to draw at 0 - while (j < region.size.x) { - j += size.x; - if (spacing <= 0) { - workspace->draw_line(Point2(j, 0), Point2(j, region.size.y), c); - } else { - workspace->draw_rect(Rect2(Point2(j, 0), Size2(spacing, region.size.y)), c); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + float j = -size.x; //make sure to draw at 0 + while (j < region.size.x) { + j += size.x; + if (spacing <= 0) { + workspace->draw_line(Point2(j, 0), Point2(j, region.size.y), c); + } else { + workspace->draw_rect(Rect2(Point2(j, 0), Size2(spacing, region.size.y)), c); + } + j += spacing; } - j += spacing; - } - j = -size.y; //make sure to draw at 0 - while (j < region.size.y) { - j += size.y; - if (spacing <= 0) { - workspace->draw_line(Point2(0, j), Point2(region.size.x, j), c); - } else { - workspace->draw_rect(Rect2(Point2(0, j), Size2(region.size.x, spacing)), c); + j = -size.y; //make sure to draw at 0 + while (j < region.size.y) { + j += size.y; + if (spacing <= 0) { + workspace->draw_line(Point2(0, j), Point2(region.size.x, j), c); + } else { + workspace->draw_rect(Rect2(Point2(0, j), Size2(region.size.x, spacing)), c); + } + j += spacing; } - j += spacing; } } } #define MIN_DISTANCE_SQUARED 10 -void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { +void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { - if (get_current_tile() >= 0 && !tile_set.is_null()) { + if (get_current_tile() >= 0 && !tileset.is_null()) { Ref<InputEventMouseButton> mb = p_ie; Ref<InputEventMouseMotion> mm = p_ie; static bool dragging; static bool erasing; - int spacing = tile_set->autotile_get_spacing(get_current_tile()); - Vector2 size = tile_set->autotile_get_size(get_current_tile()); + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); switch (edit_mode) { case EDITMODE_ICON: { if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); - tile_set->autotile_set_icon_coordinate(get_current_tile(), coord); - Rect2 region = tile_set->tile_get_region(get_current_tile()); + tileset->autotile_set_icon_coordinate(get_current_tile(), coord); + Rect2 region = tileset->tile_get_region(get_current_tile()); region.size = size; coord.x *= (spacing + size.x); coord.y *= (spacing + size.y); region.position += coord; - autotile_list->set_item_icon_region(current_item_index, region); + tile_list->set_item_icon_region(current_item_index, region); workspace->update(); } } @@ -805,7 +777,7 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); pos = mb->get_position() - pos; uint16_t bit; - if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { + if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (pos.x < size.x / 2) { if (pos.y < size.y / 2) { bit = TileSet::BIND_TOPLEFT; @@ -819,7 +791,7 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { bit = TileSet::BIND_BOTTOMRIGHT; } } - } else if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { if (pos.x < size.x / 3) { if (pos.y < size.y / 3) { bit = TileSet::BIND_TOPLEFT; @@ -846,13 +818,13 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } - uint16_t mask = tile_set->autotile_get_bitmask(get_current_tile(), coord); + uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); if (erasing) { mask &= ~bit; } else { mask |= bit; } - tile_set->autotile_set_bitmask(get_current_tile(), coord, mask); + tileset->autotile_set_bitmask(get_current_tile(), coord, mask); workspace->update(); } } else { @@ -868,7 +840,7 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); pos = mm->get_position() - pos; uint16_t bit; - if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { + if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (pos.x < size.x / 2) { if (pos.y < size.y / 2) { bit = TileSet::BIND_TOPLEFT; @@ -882,7 +854,7 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { bit = TileSet::BIND_BOTTOMRIGHT; } } - } else if (tile_set->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { if (pos.x < size.x / 3) { if (pos.y < size.y / 3) { bit = TileSet::BIND_TOPLEFT; @@ -909,13 +881,13 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } - uint16_t mask = tile_set->autotile_get_bitmask(get_current_tile(), coord); + uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); if (erasing) { mask &= ~bit; } else { mask |= bit; } - tile_set->autotile_set_bitmask(get_current_tile(), coord, mask); + tileset->autotile_set_bitmask(get_current_tile(), coord, mask); workspace->update(); } } @@ -924,9 +896,12 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { case EDITMODE_OCCLUSION: case EDITMODE_NAVIGATION: case EDITMODE_PRIORITY: { - Vector2 shape_anchor = edited_shape_coord; - shape_anchor.x *= (size.x + spacing); - shape_anchor.y *= (size.y + spacing); + Vector2 shape_anchor = Vector2(0, 0); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + shape_anchor = edited_shape_coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); + } if (tools[TOOL_SELECT]->is_pressed()) { if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { @@ -939,23 +914,25 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } - Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); - if (edited_shape_coord != coord) { - edited_shape_coord = coord; - edited_occlusion_shape = tile_set->autotile_get_light_occluder(get_current_tile(), edited_shape_coord); - edited_navigation_shape = tile_set->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord); - Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(get_current_tile()); - bool found_collision_shape = false; - for (int i = 0; i < sd.size(); i++) { - if (sd[i].autotile_coord == coord) { - edited_collision_shape = sd[i].shape; - found_collision_shape = true; - break; + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); + if (edited_shape_coord != coord) { + edited_shape_coord = coord; + edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord); + edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord); + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); + bool found_collision_shape = false; + for (int i = 0; i < sd.size(); i++) { + if (sd[i].autotile_coord == coord) { + edited_collision_shape = sd[i].shape; + found_collision_shape = true; + break; + } } + if (!found_collision_shape) + edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); + select_coord(edited_shape_coord); } - if (!found_collision_shape) - edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); - select_coord(edited_shape_coord); } workspace->update(); } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { @@ -1023,8 +1000,6 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) { - if (!tools[TOOL_SELECT]->is_disabled()) - tools[TOOL_SELECT]->set_disabled(true); if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { @@ -1046,14 +1021,14 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { int t_id = get_current_tile(); if (t_id >= 0) { if (edit_mode == EDITMODE_COLLISION) { - Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(t_id); + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id); for (int i = 0; i < sd.size(); i++) { - if (sd[i].autotile_coord == edited_shape_coord) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) { Ref<ConvexPolygonShape2D> shape = sd[i].shape; if (!shape.is_null()) { sd.remove(i); - tile_set->tile_set_shapes(get_current_tile(), sd); + tileset->tile_set_shapes(get_current_tile(), sd); edited_collision_shape = Ref<Shape2D>(); workspace->update(); } @@ -1061,25 +1036,30 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } else if (edit_mode == EDITMODE_OCCLUSION) { - Map<Vector2, Ref<OccluderPolygon2D> > map = tile_set->autotile_get_light_oclusion_map(t_id); - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tile_set->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); - break; + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); + for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { + if (E->key() == edited_shape_coord) { + tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + break; + } } - } + } else + tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>()); edited_occlusion_shape = Ref<OccluderPolygon2D>(); workspace->update(); } else if (edit_mode == EDITMODE_NAVIGATION) { - Map<Vector2, Ref<NavigationPolygon> > map = tile_set->autotile_get_navigation_map(t_id); - for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tile_set->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); - break; + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); + for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { + if (E->key() == edited_shape_coord) { + tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); + break; + } } - } - + } else + tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>()); edited_navigation_shape = Ref<NavigationPolygon>(); workspace->update(); } @@ -1092,8 +1072,6 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) { if (creating_shape) { close_shape(shape_anchor); - if (tools[TOOL_SELECT]->is_disabled()) - tools[TOOL_SELECT]->set_disabled(false); } } } else if (mm.is_valid()) { @@ -1117,17 +1095,17 @@ void AutotileEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } -void AutotileEditor::_on_tool_clicked(int p_tool) { +void TileSetEditor::_on_tool_clicked(int p_tool) { if (p_tool == BITMASK_COPY) { - bitmask_map_copy = tile_set->autotile_get_bitmask_map(get_current_tile()); + bitmask_map_copy = tileset->autotile_get_bitmask_map(get_current_tile()); } else if (p_tool == BITMASK_PASTE) { - tile_set->autotile_clear_bitmask_map(get_current_tile()); + tileset->autotile_clear_bitmask_map(get_current_tile()); for (Map<Vector2, uint16_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) { - tile_set->autotile_set_bitmask(get_current_tile(), E->key(), E->value()); + tileset->autotile_set_bitmask(get_current_tile(), E->key(), E->value()); } workspace->update(); } else if (p_tool == BITMASK_CLEAR) { - tile_set->autotile_clear_bitmask_map(get_current_tile()); + tileset->autotile_clear_bitmask_map(get_current_tile()); workspace->update(); } else if (p_tool == SHAPE_DELETE) { if (creating_shape) { @@ -1138,7 +1116,7 @@ void AutotileEditor::_on_tool_clicked(int p_tool) { switch (edit_mode) { case EDITMODE_COLLISION: { if (!edited_collision_shape.is_null()) { - Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(get_current_tile()); + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); int index; for (int i = 0; i < sd.size(); i++) { if (sd[i].shape == edited_collision_shape) { @@ -1148,7 +1126,7 @@ void AutotileEditor::_on_tool_clicked(int p_tool) { } if (index >= 0) { sd.remove(index); - tile_set->tile_set_shapes(get_current_tile(), sd); + tileset->tile_set_shapes(get_current_tile(), sd); edited_collision_shape = Ref<Shape2D>(); current_shape.resize(0); workspace->update(); @@ -1157,7 +1135,7 @@ void AutotileEditor::_on_tool_clicked(int p_tool) { } break; case EDITMODE_NAVIGATION: { if (!edited_navigation_shape.is_null()) { - tile_set->autotile_set_navigation_polygon(get_current_tile(), Ref<NavigationPolygon>(), edited_shape_coord); + tileset->autotile_set_navigation_polygon(get_current_tile(), Ref<NavigationPolygon>(), edited_shape_coord); edited_navigation_shape = Ref<NavigationPolygon>(); current_shape.resize(0); workspace->update(); @@ -1165,7 +1143,7 @@ void AutotileEditor::_on_tool_clicked(int p_tool) { } break; case EDITMODE_OCCLUSION: { if (!edited_occlusion_shape.is_null()) { - tile_set->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); edited_occlusion_shape = Ref<OccluderPolygon2D>(); current_shape.resize(0); workspace->update(); @@ -1188,15 +1166,22 @@ void AutotileEditor::_on_tool_clicked(int p_tool) { scale *= 2; workspace->set_scale(Vector2(scale, scale)); workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale); + } else if (p_tool == TOOL_SELECT) { + if (creating_shape) { + //Cancel Creation + creating_shape = false; + current_shape.resize(0); + workspace->update(); + } } } -void AutotileEditor::_on_priority_changed(float val) { - tile_set->autotile_set_subtile_priority(get_current_tile(), edited_shape_coord, (int)val); +void TileSetEditor::_on_priority_changed(float val) { + tileset->autotile_set_subtile_priority(get_current_tile(), edited_shape_coord, (int)val); workspace->update(); } -void AutotileEditor::_on_grid_snap_toggled(bool p_val) { +void TileSetEditor::_on_grid_snap_toggled(bool p_val) { if (p_val) hb_grid->show(); else @@ -1204,40 +1189,40 @@ void AutotileEditor::_on_grid_snap_toggled(bool p_val) { workspace->update(); } -void AutotileEditor::_set_snap_step_x(float p_val) { +void TileSetEditor::_set_snap_step_x(float p_val) { snap_step.x = p_val; workspace->update(); } -void AutotileEditor::_set_snap_step_y(float p_val) { +void TileSetEditor::_set_snap_step_y(float p_val) { snap_step.y = p_val; workspace->update(); } -void AutotileEditor::_set_snap_off_x(float p_val) { +void TileSetEditor::_set_snap_off_x(float p_val) { snap_offset.x = p_val; workspace->update(); } -void AutotileEditor::_set_snap_off_y(float p_val) { +void TileSetEditor::_set_snap_off_y(float p_val) { snap_offset.y = p_val; workspace->update(); } -void AutotileEditor::_set_snap_sep_x(float p_val) { +void TileSetEditor::_set_snap_sep_x(float p_val) { snap_separation.x = p_val; workspace->update(); } -void AutotileEditor::_set_snap_sep_y(float p_val) { +void TileSetEditor::_set_snap_sep_y(float p_val) { snap_separation.y = p_val; workspace->update(); } -void AutotileEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted) { +void TileSetEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted) { - Vector2 size = tile_set->autotile_get_size(get_current_tile()); - int spacing = tile_set->autotile_get_spacing(get_current_tile()); - Rect2 region = tile_set->tile_get_region(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Rect2 region = tileset->tile_get_region(get_current_tile()); coord.x *= (size.x + spacing); coord.y *= (size.y + spacing); workspace->draw_rect(Rect2(0, 0, region.size.x, coord.y), Color(0.5, 0.5, 0.5, 0.5)); @@ -1255,7 +1240,7 @@ void AutotileEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &o } } -void AutotileEditor::draw_grid_snap() { +void TileSetEditor::draw_grid_snap() { if (tools[SHAPE_GRID_SNAP]->is_pressed()) { Color grid_color = Color(0.39, 0, 1, 0.2f); Size2 s = workspace->get_size(); @@ -1296,7 +1281,7 @@ void AutotileEditor::draw_grid_snap() { } } -void AutotileEditor::draw_polygon_shapes() { +void TileSetEditor::draw_polygon_shapes() { int t_id = get_current_tile(); if (t_id < 0) @@ -1304,19 +1289,23 @@ void AutotileEditor::draw_polygon_shapes() { switch (edit_mode) { case EDITMODE_COLLISION: { - Vector<TileSet::ShapeData> sd = tile_set->tile_get_shapes(t_id); + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id); for (int i = 0; i < sd.size(); i++) { - Vector2 coord = sd[i].autotile_coord; - Vector2 anchor = tile_set->autotile_get_size(t_id); - anchor.x += tile_set->autotile_get_spacing(t_id); - anchor.y += tile_set->autotile_get_spacing(t_id); - anchor.x *= coord.x; - anchor.y *= coord.y; + Vector2 coord = Vector2(0, 0); + Vector2 anchor = Vector2(0, 0); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + coord = sd[i].autotile_coord; + anchor = tileset->autotile_get_size(t_id); + anchor.x += tileset->autotile_get_spacing(t_id); + anchor.y += tileset->autotile_get_spacing(t_id); + anchor.x *= coord.x; + anchor.y *= coord.y; + } Ref<ConvexPolygonShape2D> shape = sd[i].shape; if (shape.is_valid()) { Color c_bg; Color c_border; - if (coord == edited_shape_coord && sd[i].shape == edited_collision_shape) { + if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || coord == edited_shape_coord) && sd[i].shape == edited_collision_shape) { c_bg = Color(0, 1, 1, 0.5); c_border = Color(0, 1, 1); } else { @@ -1339,7 +1328,7 @@ void AutotileEditor::draw_polygon_shapes() { if (polygon.size() > 2) { workspace->draw_polygon(polygon, colors); } - if (coord == edited_shape_coord) { + if (coord == edited_shape_coord || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { for (int j = 0; j < shape->get_points().size() - 1; j++) { workspace->draw_line(shape->get_points()[j] + anchor, shape->get_points()[j + 1] + anchor, c_border, 1, true); } @@ -1354,47 +1343,73 @@ void AutotileEditor::draw_polygon_shapes() { } } break; case EDITMODE_OCCLUSION: { - Map<Vector2, Ref<OccluderPolygon2D> > map = tile_set->autotile_get_light_oclusion_map(t_id); - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { - Vector2 coord = E->key(); - Vector2 anchor = tile_set->autotile_get_size(t_id); - anchor.x += tile_set->autotile_get_spacing(t_id); - anchor.y += tile_set->autotile_get_spacing(t_id); - anchor.x *= coord.x; - anchor.y *= coord.y; - Ref<OccluderPolygon2D> shape = E->value(); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + Ref<OccluderPolygon2D> shape = edited_occlusion_shape; if (shape.is_valid()) { - Color c_bg; - Color c_border; - if (coord == edited_shape_coord && shape == edited_occlusion_shape) { - c_bg = Color(0, 1, 1, 0.5); - c_border = Color(0, 1, 1); - } else { - c_bg = Color(0.9, 0.7, 0.07, 0.5); - c_border = Color(0.9, 0.7, 0.07, 1); - } + Color c_bg = Color(0, 1, 1, 0.5); + Color c_border = Color(0, 1, 1); + Vector<Vector2> polygon; Vector<Color> colors; - if (shape == edited_occlusion_shape && current_shape.size() > 2) { + for (int j = 0; j < shape->get_polygon().size(); j++) { + polygon.push_back(shape->get_polygon()[j]); + colors.push_back(c_bg); + } + workspace->draw_polygon(polygon, colors); + + for (int j = 0; j < shape->get_polygon().size() - 1; j++) { + workspace->draw_line(shape->get_polygon()[j], shape->get_polygon()[j + 1], c_border, 1, true); + } + workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1], shape->get_polygon()[0], c_border, 1, true); + if (shape == edited_occlusion_shape) { for (int j = 0; j < current_shape.size(); j++) { - polygon.push_back(current_shape[j]); - colors.push_back(c_bg); - } - } else { - for (int j = 0; j < shape->get_polygon().size(); j++) { - polygon.push_back(shape->get_polygon()[j] + anchor); - colors.push_back(c_bg); + workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0)); } } - workspace->draw_polygon(polygon, colors); - if (coord == edited_shape_coord) { - for (int j = 0; j < shape->get_polygon().size() - 1; j++) { - workspace->draw_line(shape->get_polygon()[j] + anchor, shape->get_polygon()[j + 1] + anchor, c_border, 1, true); + } + } else { + Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); + for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { + Vector2 coord = E->key(); + Vector2 anchor = tileset->autotile_get_size(t_id); + anchor.x += tileset->autotile_get_spacing(t_id); + anchor.y += tileset->autotile_get_spacing(t_id); + anchor.x *= coord.x; + anchor.y *= coord.y; + Ref<OccluderPolygon2D> shape = E->value(); + if (shape.is_valid()) { + Color c_bg; + Color c_border; + if (coord == edited_shape_coord && shape == edited_occlusion_shape) { + c_bg = Color(0, 1, 1, 0.5); + c_border = Color(0, 1, 1); + } else { + c_bg = Color(0.9, 0.7, 0.07, 0.5); + c_border = Color(0.9, 0.7, 0.07, 1); } - workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1] + anchor, shape->get_polygon()[0] + anchor, c_border, 1, true); - if (shape == edited_occlusion_shape) { + Vector<Vector2> polygon; + Vector<Color> colors; + if (shape == edited_occlusion_shape && current_shape.size() > 2) { for (int j = 0; j < current_shape.size(); j++) { - workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0)); + polygon.push_back(current_shape[j]); + colors.push_back(c_bg); + } + } else { + for (int j = 0; j < shape->get_polygon().size(); j++) { + polygon.push_back(shape->get_polygon()[j] + anchor); + colors.push_back(c_bg); + } + } + workspace->draw_polygon(polygon, colors); + if (coord == edited_shape_coord) { + for (int j = 0; j < shape->get_polygon().size() - 1; j++) { + workspace->draw_line(shape->get_polygon()[j] + anchor, shape->get_polygon()[j + 1] + anchor, c_border, 1, true); + } + workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1] + anchor, shape->get_polygon()[0] + anchor, c_border, 1, true); + if (shape == edited_occlusion_shape) { + for (int j = 0; j < current_shape.size(); j++) { + workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0)); + } } } } @@ -1402,49 +1417,81 @@ void AutotileEditor::draw_polygon_shapes() { } } break; case EDITMODE_NAVIGATION: { - Map<Vector2, Ref<NavigationPolygon> > map = tile_set->autotile_get_navigation_map(t_id); - for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { - Vector2 coord = E->key(); - Vector2 anchor = tile_set->autotile_get_size(t_id); - anchor.x += tile_set->autotile_get_spacing(t_id); - anchor.y += tile_set->autotile_get_spacing(t_id); - anchor.x *= coord.x; - anchor.y *= coord.y; - Ref<NavigationPolygon> shape = E->value(); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + Ref<NavigationPolygon> shape = edited_navigation_shape; + if (shape.is_valid()) { - Color c_bg; - Color c_border; - if (coord == edited_shape_coord && shape == edited_navigation_shape) { - c_bg = Color(0, 1, 1, 0.5); - c_border = Color(0, 1, 1); - } else { - c_bg = Color(0.9, 0.7, 0.07, 0.5); - c_border = Color(0.9, 0.7, 0.07, 1); - } + Color c_bg = Color(0, 1, 1, 0.5); + Color c_border = Color(0, 1, 1); + Vector<Vector2> polygon; Vector<Color> colors; - if (shape == edited_navigation_shape && current_shape.size() > 2) { - for (int j = 0; j < current_shape.size(); j++) { - polygon.push_back(current_shape[j]); - colors.push_back(c_bg); - } - } else if (shape->get_polygon_count() > 0) { + + PoolVector<Vector2> vertices = shape->get_vertices(); + for (int j = 0; j < shape->get_polygon(0).size(); j++) { + polygon.push_back(vertices[shape->get_polygon(0)[j]]); + colors.push_back(c_bg); + } + workspace->draw_polygon(polygon, colors); + + if (shape->get_polygon_count() > 0) { PoolVector<Vector2> vertices = shape->get_vertices(); - for (int j = 0; j < shape->get_polygon(0).size(); j++) { - polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); - colors.push_back(c_bg); + for (int j = 0; j < shape->get_polygon(0).size() - 1; j++) { + workspace->draw_line(vertices[shape->get_polygon(0)[j]], vertices[shape->get_polygon(0)[j + 1]], c_border, 1, true); + } + if (shape == edited_navigation_shape) { + for (int j = 0; j < current_shape.size(); j++) { + workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0)); + } } } - workspace->draw_polygon(polygon, colors); - if (coord == edited_shape_coord) { - if (shape->get_polygon_count() > 0) { + } + + } else { + Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); + for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { + Vector2 coord = E->key(); + Vector2 anchor = tileset->autotile_get_size(t_id); + anchor.x += tileset->autotile_get_spacing(t_id); + anchor.y += tileset->autotile_get_spacing(t_id); + anchor.x *= coord.x; + anchor.y *= coord.y; + Ref<NavigationPolygon> shape = E->value(); + if (shape.is_valid()) { + Color c_bg; + Color c_border; + if (coord == edited_shape_coord && shape == edited_navigation_shape) { + c_bg = Color(0, 1, 1, 0.5); + c_border = Color(0, 1, 1); + } else { + c_bg = Color(0.9, 0.7, 0.07, 0.5); + c_border = Color(0.9, 0.7, 0.07, 1); + } + Vector<Vector2> polygon; + Vector<Color> colors; + if (shape == edited_navigation_shape && current_shape.size() > 2) { + for (int j = 0; j < current_shape.size(); j++) { + polygon.push_back(current_shape[j]); + colors.push_back(c_bg); + } + } else if (shape->get_polygon_count() > 0) { PoolVector<Vector2> vertices = shape->get_vertices(); - for (int j = 0; j < shape->get_polygon(0).size() - 1; j++) { - workspace->draw_line(vertices[shape->get_polygon(0)[j]] + anchor, vertices[shape->get_polygon(0)[j + 1]] + anchor, c_border, 1, true); + for (int j = 0; j < shape->get_polygon(0).size(); j++) { + polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); + colors.push_back(c_bg); } - if (shape == edited_navigation_shape) { - for (int j = 0; j < current_shape.size(); j++) { - workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0)); + } + workspace->draw_polygon(polygon, colors); + if (coord == edited_shape_coord) { + if (shape->get_polygon_count() > 0) { + PoolVector<Vector2> vertices = shape->get_vertices(); + for (int j = 0; j < shape->get_polygon(0).size() - 1; j++) { + workspace->draw_line(vertices[shape->get_polygon(0)[j]] + anchor, vertices[shape->get_polygon(0)[j + 1]] + anchor, c_border, 1, true); + } + if (shape == edited_navigation_shape) { + for (int j = 0; j < current_shape.size(); j++) { + workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0)); + } } } } @@ -1461,7 +1508,7 @@ void AutotileEditor::draw_polygon_shapes() { } } -void AutotileEditor::close_shape(const Vector2 &shape_anchor) { +void TileSetEditor::close_shape(const Vector2 &shape_anchor) { creating_shape = false; @@ -1486,7 +1533,11 @@ void AutotileEditor::close_shape(const Vector2 &shape_anchor) { shape->set_points(segments); - tile_set->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + tileset->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord); + else + tileset->tile_set_shape(get_current_tile(), 0, shape); + edited_collision_shape = shape; } @@ -1506,7 +1557,10 @@ void AutotileEditor::close_shape(const Vector2 &shape_anchor) { w = PoolVector<Vector2>::Write(); shape->set_polygon(polygon); - tile_set->autotile_set_light_occluder(get_current_tile(), shape, edited_shape_coord); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + tileset->autotile_set_light_occluder(get_current_tile(), shape, edited_shape_coord); + else + tileset->tile_set_light_occluder(get_current_tile(), shape); edited_occlusion_shape = shape; tools[TOOL_SELECT]->set_pressed(true); workspace->update(); @@ -1526,55 +1580,99 @@ void AutotileEditor::close_shape(const Vector2 &shape_anchor) { w = PoolVector<Vector2>::Write(); shape->set_vertices(polygon); shape->add_polygon(indices); - tile_set->autotile_set_navigation_polygon(get_current_tile(), shape, edited_shape_coord); + + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + tileset->autotile_set_navigation_polygon(get_current_tile(), shape, edited_shape_coord); + else + tileset->tile_set_navigation_polygon(get_current_tile(), shape); edited_navigation_shape = shape; tools[TOOL_SELECT]->set_pressed(true); workspace->update(); } + tileset->_change_notify(""); } -void AutotileEditor::select_coord(const Vector2 &coord) { - int spacing = tile_set->autotile_get_spacing(get_current_tile()); - Vector2 size = tile_set->autotile_get_size(get_current_tile()); - Vector2 shape_anchor = coord; - shape_anchor.x *= (size.x + spacing); - shape_anchor.y *= (size.y + spacing); - if (edit_mode == EDITMODE_COLLISION) { - current_shape.resize(0); - if (edited_collision_shape.is_valid()) { - for (int j = 0; j < edited_collision_shape->get_points().size(); j++) { - current_shape.push_back(edited_collision_shape->get_points()[j] + shape_anchor); +void TileSetEditor::select_coord(const Vector2 &coord) { + current_shape = PoolVector2Array(); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0)) + edited_collision_shape = tileset->tile_get_shape(get_current_tile(), 0); + if (edited_occlusion_shape != tileset->tile_get_light_occluder(get_current_tile())) + edited_occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); + if (edited_navigation_shape != tileset->tile_get_navigation_polygon(get_current_tile())) + edited_navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile()); + + if (edit_mode == EDITMODE_COLLISION) { + current_shape.resize(0); + if (edited_collision_shape.is_valid()) { + for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { + current_shape.push_back(edited_collision_shape->get_points()[i]); + } } - } - } else if (edit_mode == EDITMODE_OCCLUSION) { - current_shape.resize(0); - if (edited_occlusion_shape.is_valid()) { - for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) { - current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + shape_anchor); + } else if (edit_mode == EDITMODE_OCCLUSION) { + current_shape.resize(0); + if (edited_occlusion_shape.is_valid()) { + for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) { + current_shape.push_back(edited_occlusion_shape->get_polygon()[i]); + } + } + } else if (edit_mode == EDITMODE_NAVIGATION) { + current_shape.resize(0); + if (edited_navigation_shape.is_valid()) { + if (edited_navigation_shape->get_polygon_count() > 0) { + PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices(); + for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { + current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]]); + } + } } } - } else if (edit_mode == EDITMODE_NAVIGATION) { - current_shape.resize(0); - if (edited_navigation_shape.is_valid()) { - if (edited_navigation_shape->get_polygon_count() > 0) { - PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices(); - for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { - current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + shape_anchor); + } else { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + Vector2 shape_anchor = coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); + if (edit_mode == EDITMODE_COLLISION) { + current_shape.resize(0); + if (edited_collision_shape.is_valid()) { + for (int j = 0; j < edited_collision_shape->get_points().size(); j++) { + current_shape.push_back(edited_collision_shape->get_points()[j] + shape_anchor); + } + } + } else if (edit_mode == EDITMODE_OCCLUSION) { + current_shape.resize(0); + if (edited_occlusion_shape.is_valid()) { + for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) { + current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + shape_anchor); + } + } + } else if (edit_mode == EDITMODE_NAVIGATION) { + current_shape.resize(0); + if (edited_navigation_shape.is_valid()) { + if (edited_navigation_shape->get_polygon_count() > 0) { + PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices(); + for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { + current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + shape_anchor); + } } } } } } -Vector2 AutotileEditor::snap_point(const Vector2 &point) { +Vector2 TileSetEditor::snap_point(const Vector2 &point) { Vector2 p = point; Vector2 coord = edited_shape_coord; - Vector2 tile_size = tile_set->autotile_get_size(get_current_tile()); - int spacing = tile_set->autotile_get_spacing(get_current_tile()); + Vector2 tile_size = tileset->autotile_get_size(get_current_tile()); + int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 anchor = coord; anchor.x *= (tile_size.x + spacing); anchor.y *= (tile_size.y + spacing); Rect2 region(anchor, tile_size); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) + region.position = Point2(0, 0); + if (tools[SHAPE_GRID_SNAP]->is_pressed()) { p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x); p.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p.y, snap_separation.y); @@ -1592,86 +1690,134 @@ Vector2 AutotileEditor::snap_point(const Vector2 &point) { return p; } -void AutotileEditor::edit(Object *p_node) { +void TileSetEditor::update_tile_list() { + int selected_tile = get_current_tile(); - tile_set = Ref<TileSet>(Object::cast_to<TileSet>(p_node)); - tile_set->add_change_receptor(this); - helper->set_tileset(tile_set); + if (selected_tile < 0) + selected_tile = 0; - autotile_list->clear(); + helper->set_tileset(tileset); + + tile_list->clear(); List<int> ids; - tile_set->get_tile_list(&ids); + tileset->get_tile_list(&ids); for (List<int>::Element *E = ids.front(); E; E = E->next()) { - if (tile_set->tile_get_is_autotile(E->get())) { - autotile_list->add_item(tile_set->tile_get_name(E->get())); - autotile_list->set_item_metadata(autotile_list->get_item_count() - 1, E->get()); - autotile_list->set_item_icon(autotile_list->get_item_count() - 1, tile_set->tile_get_texture(E->get())); - Rect2 region = tile_set->tile_get_region(E->get()); - region.size = tile_set->autotile_get_size(E->get()); - Vector2 pos = tile_set->autotile_get_icon_coordinate(E->get()); - pos.x *= (tile_set->autotile_get_spacing(E->get()) + region.size.x); - pos.y *= (tile_set->autotile_get_spacing(E->get()) + region.size.y); + tile_list->add_item(tileset->tile_get_name(E->get())); + tile_list->set_item_metadata(tile_list->get_item_count() - 1, E->get()); + tile_list->set_item_icon(tile_list->get_item_count() - 1, tileset->tile_get_texture(E->get())); + Rect2 region = tileset->tile_get_region(E->get()); + if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) { + region.size = tileset->autotile_get_size(E->get()); + Vector2 pos = tileset->autotile_get_icon_coordinate(E->get()); + pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x); + pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y); region.position += pos; - autotile_list->set_item_icon_region(autotile_list->get_item_count() - 1, region); } + tile_list->set_item_icon_region(tile_list->get_item_count() - 1, region); } - if (autotile_list->get_item_count() > 0) { - autotile_list->select(0); - _on_autotile_selected(0); + if (tile_list->get_item_count() > 0 && selected_tile < tile_list->get_item_count()) { + tile_list->select(selected_tile); + _on_tile_list_selected(selected_tile); } helper->_change_notify(""); } -int AutotileEditor::get_current_tile() { +void TileSetEditor::update_tile_list_icon() { + List<int> ids; + tileset->get_tile_list(&ids); + int current_idx = 0; + for (List<int>::Element *E = ids.front(); E; E = E->next()) { + if (current_idx >= tile_list->get_item_count()) + break; + + Rect2 region = tileset->tile_get_region(E->get()); + if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) { + region.size = tileset->autotile_get_size(E->get()); + Vector2 pos = tileset->autotile_get_icon_coordinate(E->get()); + pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x); + pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y); + region.position += pos; + } + tile_list->set_item_metadata(current_idx, E->get()); + tile_list->set_item_icon(current_idx, tileset->tile_get_texture(E->get())); + tile_list->set_item_icon_region(current_idx, region); + tile_list->set_item_text(current_idx, tileset->tile_get_name(E->get())); + current_idx += 1; + } + tile_list->update(); +} + +void TileSetEditor::update_workspace_tile_mode() { + if (get_current_tile() < 0) + return; + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { + tool_editmode[EDITMODE_COLLISION]->set_pressed(true); + _on_edit_mode_changed(EDITMODE_COLLISION); + } else { + select_coord(Vector2(0, 0)); + } + + tool_editmode[EDITMODE_ICON]->hide(); + tool_editmode[EDITMODE_BITMASK]->hide(); + tool_editmode[EDITMODE_PRIORITY]->hide(); + property_editor->hide(); + } else { + tool_editmode[EDITMODE_ICON]->show(); + tool_editmode[EDITMODE_BITMASK]->show(); + tool_editmode[EDITMODE_PRIORITY]->show(); + property_editor->show(); + } +} - if (autotile_list->get_selected_items().size() == 0) +int TileSetEditor::get_current_tile() { + if (tile_list->get_selected_items().size() == 0) return -1; else - return autotile_list->get_item_metadata(autotile_list->get_selected_items()[0]); + return tile_list->get_item_metadata(tile_list->get_selected_items()[0]); } -void AutotileEditorHelper::set_tileset(const Ref<TileSet> &p_tileset) { +void TileSetEditorHelper::set_tileset(const Ref<TileSet> &p_tileset) { - tile_set = p_tileset; + tileset = p_tileset; } -bool AutotileEditorHelper::_set(const StringName &p_name, const Variant &p_value) { +bool TileSetEditorHelper::_set(const StringName &p_name, const Variant &p_value) { - if (autotile_editor->get_current_tile() < 0 || tile_set.is_null()) + if (selected_tile < 0 || tileset.is_null()) return false; String name = p_name.operator String(); bool v = false; if (name == "bitmask_mode") { - tile_set->set(String::num(autotile_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v); + tileset->set(String::num(selected_tile, 0) + "/autotile/bitmask_mode", p_value, &v); } else if (name.left(7) == "layout/") { - tile_set->set(String::num(autotile_editor->get_current_tile(), 0) + "/autotile" + name.right(6), p_value, &v); + tileset->set(String::num(selected_tile, 0) + "/autotile" + name.right(6), p_value, &v); } if (v) { - tile_set->_change_notify(""); - autotile_editor->workspace->update(); + tileset->_change_notify("autotile"); } return v; } -bool AutotileEditorHelper::_get(const StringName &p_name, Variant &r_ret) const { +bool TileSetEditorHelper::_get(const StringName &p_name, Variant &r_ret) const { - if (autotile_editor->get_current_tile() < 0 || tile_set.is_null()) + if (selected_tile < 0 || tileset.is_null()) return false; String name = p_name.operator String(); bool v = false; if (name == "bitmask_mode") { - r_ret = tile_set->get(String::num(autotile_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", &v); + r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile/bitmask_mode", &v); } else if (name.left(7) == "layout/") { - r_ret = tile_set->get(String::num(autotile_editor->get_current_tile(), 0) + "/autotile" + name.right(6), &v); + r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile" + name.right(6), &v); } return v; } -void AutotileEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const { +void TileSetEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const { - if (autotile_editor->get_current_tile() < 0 || tile_set.is_null()) + if (selected_tile < 0 || tileset.is_null()) return; p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3")); @@ -1679,7 +1825,71 @@ void AutotileEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const p_list->push_back(PropertyInfo(Variant::INT, "layout/spacing", PROPERTY_HINT_RANGE, "0,256,1")); } -AutotileEditorHelper::AutotileEditorHelper(AutotileEditor *p_autotile_editor) { +TileSetEditorHelper::TileSetEditorHelper(TileSetEditor *p_tileset_editor) { + + tileset_editor = p_tileset_editor; +} + +void TileSetEditorPlugin::edit(Object *p_node) { + + if (Object::cast_to<TileSet>(p_node)) { + tileset_editor->edit(Object::cast_to<TileSet>(p_node)); + tileset_editor->show(); + tileset_editor->texture_region_editor->edit(p_node); + } else + tileset_editor->hide(); +} + +bool TileSetEditorPlugin::handles(Object *p_node) const { + + return p_node->is_class("TileSet"); +} + +void TileSetEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) { + tileset_editor->show(); + tileset_editor->menu->show(); + tileset_editor_button->show(); + tileset_editor->side_panel->show(); + if (tileset_editor_button->is_pressed()) { + tileset_editor->bottom_panel->show(); + } + texture_region_button->show(); + if (texture_region_button->is_pressed()) + tileset_editor->texture_region_editor->show(); + } else { + tileset_editor->hide(); + tileset_editor->menu->hide(); + tileset_editor->side_panel->hide(); + tileset_editor->bottom_panel->hide(); + tileset_editor_button->hide(); + texture_region_button->hide(); + tileset_editor->texture_region_editor->hide(); + } +} + +TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) { + + tileset_editor = memnew(TileSetEditor(p_node)); + + add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, tileset_editor); + tileset_editor->set_anchors_and_margins_preset(Control::PRESET_TOP_WIDE); + tileset_editor->set_end(Point2(0, 22)); + tileset_editor->hide(); + + tileset_editor->texture_region_editor = memnew(TextureRegionEditor(p_node)); + texture_region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), tileset_editor->texture_region_editor); + texture_region_button->set_tooltip(TTR("Texture Region Editor")); + + tileset_editor->texture_region_editor->set_custom_minimum_size(Size2(0, 200)); + tileset_editor->texture_region_editor->hide(); + texture_region_button->hide(); - autotile_editor = p_autotile_editor; + add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE, tileset_editor->side_panel); + tileset_editor->side_panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); + tileset_editor->side_panel->set_custom_minimum_size(Size2(200, 0)); + tileset_editor->side_panel->hide(); + tileset_editor_button = p_node->add_bottom_panel_item(TTR("Tile Set"), tileset_editor->bottom_panel); + tileset_editor_button->hide(); } diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 30f6e2b925..0404c5236a 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -33,35 +33,38 @@ #include "editor/editor_name_dialog.h" #include "editor/editor_node.h" +#include "editor/plugins/texture_region_editor_plugin.h" #include "scene/2d/sprite.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/tile_set.h" -class AutotileEditorHelper; -class AutotileEditor : public Control { +class TileSetEditorHelper; + +class TileSetEditor : public Control { friend class TileSetEditorPlugin; - friend class AutotileEditorHelper; - GDCLASS(AutotileEditor, Control); + friend class TextureRegionEditor; + + GDCLASS(TileSetEditor, Control); enum EditMode { - EDITMODE_ICON, - EDITMODE_BITMASK, EDITMODE_COLLISION, EDITMODE_OCCLUSION, EDITMODE_NAVIGATION, + EDITMODE_BITMASK, EDITMODE_PRIORITY, + EDITMODE_ICON, EDITMODE_MAX }; - enum AutotileToolbars { + enum TileSetToolbar { TOOLBAR_DUMMY, TOOLBAR_BITMASK, TOOLBAR_SHAPE, TOOLBAR_MAX }; - enum AutotileTools { + enum TileSetTools { TOOL_SELECT, BITMASK_COPY, BITMASK_PASTE, @@ -78,13 +81,12 @@ class AutotileEditor : public Control { TOOL_MAX }; - Ref<TileSet> tile_set; + Ref<TileSet> tileset; + Ref<ConvexPolygonShape2D> edited_collision_shape; Ref<OccluderPolygon2D> edited_occlusion_shape; Ref<NavigationPolygon> edited_navigation_shape; - EditorNode *editor; - int current_item_index; Sprite *preview; ScrollContainer *scroll; @@ -114,21 +116,48 @@ class AutotileEditor : public Control { PoolVector2Array current_shape; Map<Vector2, uint16_t> bitmask_map_copy; + EditorNode *editor; + TextureRegionEditor *texture_region_editor; + Control *bottom_panel; Control *side_panel; - ItemList *autotile_list; + ItemList *tile_list; PropertyEditor *property_editor; - AutotileEditorHelper *helper; + TileSetEditorHelper *helper; + + MenuButton *menu; + ConfirmationDialog *cd; + EditorNameDialog *nd; + AcceptDialog *err_dialog; + + enum { - AutotileEditor(EditorNode *p_editor); - ~AutotileEditor(); + MENU_OPTION_ADD_ITEM, + MENU_OPTION_REMOVE_ITEM, + MENU_OPTION_CREATE_FROM_SCENE, + MENU_OPTION_MERGE_FROM_SCENE + }; + + int option; + void _menu_cbk(int p_option); + void _menu_confirm(); + void _name_dialog_confirm(const String &name); + + static void _import_node(Node *p_node, Ref<TileSet> p_library); + static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge); protected: static void _bind_methods(); void _notification(int p_what); virtual void _changed_callback(Object *p_changed, const char *p_prop); +public: + void edit(const Ref<TileSet> &p_tileset); + static Error update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge = true); + + TileSetEditor(EditorNode *p_editor); + private: - void _on_autotile_selected(int p_index); + void _on_tile_list_selected(int p_index); void _on_edit_mode_changed(int p_edit_mode); void _on_workspace_draw(); void _on_workspace_input(const Ref<InputEvent> &p_ie); @@ -142,24 +171,28 @@ private: void _set_snap_sep_x(float p_val); void _set_snap_sep_y(float p_val); + void initialize_bottom_editor(); void draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>()); void draw_grid_snap(); void draw_polygon_shapes(); void close_shape(const Vector2 &shape_anchor); void select_coord(const Vector2 &coord); Vector2 snap_point(const Vector2 &point); + void update_tile_list(); + void update_tile_list_icon(); + void update_workspace_tile_mode(); - void edit(Object *p_node); int get_current_tile(); }; -class AutotileEditorHelper : public Object { +class TileSetEditorHelper : public Object { - friend class AutotileEditor; - GDCLASS(AutotileEditorHelper, Object); + friend class TileSetEditor; + GDCLASS(TileSetEditorHelper, Object); - Ref<TileSet> tile_set; - AutotileEditor *autotile_editor; + Ref<TileSet> tileset; + TileSetEditor *tileset_editor; + int selected_tile; public: void set_tileset(const Ref<TileSet> &p_tileset); @@ -169,46 +202,7 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - AutotileEditorHelper(AutotileEditor *p_autotile_editor); -}; - -class TileSetEditor : public Control { - - friend class TileSetEditorPlugin; - GDCLASS(TileSetEditor, Control); - - Ref<TileSet> tileset; - - EditorNode *editor; - MenuButton *menu; - ConfirmationDialog *cd; - EditorNameDialog *nd; - AcceptDialog *err_dialog; - - enum { - - MENU_OPTION_ADD_ITEM, - MENU_OPTION_REMOVE_ITEM, - MENU_OPTION_CREATE_FROM_SCENE, - MENU_OPTION_MERGE_FROM_SCENE - }; - - int option; - void _menu_cbk(int p_option); - void _menu_confirm(); - void _name_dialog_confirm(const String &name); - - static void _import_node(Node *p_node, Ref<TileSet> p_library); - static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge); - -protected: - static void _bind_methods(); - -public: - void edit(const Ref<TileSet> &p_tileset); - static Error update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge = true); - - TileSetEditor(EditorNode *p_editor); + TileSetEditorHelper(TileSetEditor *p_tileset_editor); }; class TileSetEditorPlugin : public EditorPlugin { @@ -216,10 +210,10 @@ class TileSetEditorPlugin : public EditorPlugin { GDCLASS(TileSetEditorPlugin, EditorPlugin); TileSetEditor *tileset_editor; - AutotileEditor *autotile_editor; EditorNode *editor; - ToolButton *autotile_button; + ToolButton *tileset_editor_button; + ToolButton *texture_region_button; public: virtual String get_name() const { return "TileSet"; } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 8506c75a68..45622d43e8 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1885,8 +1885,6 @@ void SceneTreeDock::_local_tree_selected() { remote_tree->hide(); edit_remote->set_pressed(false); edit_local->set_pressed(true); - - _node_selected(); } void SceneTreeDock::_bind_methods() { diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 0a3e2da5e9..8f3113c816 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -536,6 +536,7 @@ void SceneTreeEditor::_notification(int p_what) { tree->connect("item_collapsed", this, "_cell_collapsed"); EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); + _editor_settings_changed(); //get_scene()->connect("tree_changed",this,"_tree_changed",Vector<Variant>(),CONNECT_DEFERRED); //get_scene()->connect("node_removed",this,"_node_removed",Vector<Variant>(),CONNECT_DEFERRED); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index e56a7f2a55..b893b098ac 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -535,15 +535,19 @@ void ScriptCreateDialog::_update_dialog() { /* Is Script created or loaded from existing file */ - if (is_new_script_created) { + if (is_built_in) { + get_ok()->set_text(TTR("Create")); + parent_name->set_editable(true); + parent_browse_button->set_disabled(false); + internal->set_disabled(!supports_built_in); + _msg_path_valid(true, TTR("Built-in script (into scene file)")); + } else if (is_new_script_created) { // New Script Created get_ok()->set_text(TTR("Create")); parent_name->set_editable(true); parent_browse_button->set_disabled(false); internal->set_disabled(!supports_built_in); - if (is_built_in) { - _msg_path_valid(true, TTR("Built-in script (into scene file)")); - } else if (is_path_valid) { + if (is_path_valid) { _msg_path_valid(true, TTR("Create new script file")); } } else { @@ -551,7 +555,7 @@ void ScriptCreateDialog::_update_dialog() { get_ok()->set_text(TTR("Load")); parent_name->set_editable(false); parent_browse_button->set_disabled(true); - internal->set_disabled(true); + internal->set_disabled(!supports_built_in); if (is_path_valid) { _msg_path_valid(true, TTR("Load existing script file")); } diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 86ab84909e..4fc73b2a8e 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -965,6 +965,14 @@ void ScriptEditorDebugger::_notification(int p_what) { reason->add_color_override("font_color", get_color("error_color", "Editor")); + bool enable_rl = EditorSettings::get_singleton()->get("docks/scene_tree/draw_relationship_lines"); + Color rl_color = EditorSettings::get_singleton()->get("docks/scene_tree/relationship_line_color"); + + if (enable_rl) { + inspect_scene_tree->add_constant_override("draw_relationship_lines", 1); + inspect_scene_tree->add_color_override("relationship_line_color", rl_color); + } else + inspect_scene_tree->add_constant_override("draw_relationship_lines", 0); } break; case NOTIFICATION_PROCESS: { @@ -1873,6 +1881,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { sc->set_v_size_flags(SIZE_EXPAND_FILL); stack_dump = memnew(Tree); + stack_dump->set_allow_reselect(true); stack_dump->set_columns(1); stack_dump->set_column_titles_visible(true); stack_dump->set_column_title(0, TTR("Stack Frames")); diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index b646fc164d..595e4951a2 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -825,12 +825,12 @@ PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) { return BulletPhysicsDirectBodyState::get_singleton(body); } -bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, MotionResult *r_result) { +bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); - return body->get_space()->test_body_motion(body, p_from, p_motion, r_result); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result); } RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) { diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 764ec2387c..885d58d98d 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -253,7 +253,7 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body); - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, MotionResult *r_result = NULL); + virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL); /* SOFT BODY API */ diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index 8d4ca6d6a7..7c051f8f17 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -98,11 +98,16 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox if (gObj == m_self_object) { return false; } else { - if (m_ignore_areas && gObj->getType() == CollisionObjectBullet::TYPE_AREA) { + + // A kinematic body can't be stopped by a rigid body since the mass of kinematic body is infinite + if (m_infinite_inertia && !btObj->isStaticOrKinematicObject()) + return false; + + if (gObj->getType() == CollisionObjectBullet::TYPE_AREA) return false; - } else if (m_self_object->has_collision_exception(gObj)) { + + if (m_self_object->has_collision_exception(gObj)) return false; - } } return true; } else { diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h index e1b0b1b421..ed6d4b7d6d 100644 --- a/modules/bullet/godot_result_callbacks.h +++ b/modules/bullet/godot_result_callbacks.h @@ -93,12 +93,12 @@ public: struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: const RigidBodyBullet *m_self_object; - const bool m_ignore_areas; + const bool m_infinite_inertia; - GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_ignore_areas) : + GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_self_object(p_self_object), - m_ignore_areas(p_ignore_areas) {} + m_infinite_inertia(p_infinite_inertia) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; }; diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 88d9c20eba..56441f7ef2 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -804,8 +804,7 @@ static Ref<SpatialMaterial> red_mat; static Ref<SpatialMaterial> blue_mat; #endif -#define IGNORE_AREAS_TRUE true -bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, PhysicsServer::MotionResult *r_result) { +bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result) { #if debug_test_motion /// Yes I know this is not good, but I've used it as fast debugging hack. @@ -839,16 +838,6 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f } #endif - ///// Release all generated manifolds - //{ - // if(p_body->get_kinematic_utilities()){ - // for(int i= p_body->get_kinematic_utilities()->m_generatedManifold.size()-1; 0<=i; --i){ - // dispatcher->releaseManifold( p_body->get_kinematic_utilities()->m_generatedManifold[i] ); - // } - // p_body->get_kinematic_utilities()->m_generatedManifold.clear(); - // } - //} - btTransform body_safe_position; G_TO_B(p_from, body_safe_position); UNSCALE_BT_BASIS(body_safe_position); @@ -857,7 +846,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f btVector3 recover_initial_position(0, 0, 0); { /// Phase one - multi shapes depenetration using margin for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - if (!recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, recover_initial_position)) { + if (!recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, recover_initial_position)) { break; } } @@ -900,7 +889,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f btTransform shape_world_to(shape_world_from); shape_world_to.getOrigin() += motion; - GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, IGNORE_AREAS_TRUE); + GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia); btResult.m_collisionFilterGroup = p_body->get_collision_layer(); btResult.m_collisionFilterMask = p_body->get_collision_mask(); @@ -926,7 +915,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f real_t l_penetration_distance = 1e20; for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - l_has_penetration = recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, delta_recover_movement, &r_recover_result); + l_has_penetration = recover_from_penetration(p_body, body_safe_position, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, delta_recover_movement, &r_recover_result); if (r_result) { #if PERFORM_INITIAL_UNSTACK @@ -955,15 +944,6 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f r_result->collider_shape = r_recover_result.other_compound_shape_index; r_result->collision_local_shape = r_recover_result.local_shape_most_recovered; - //{ /// Add manifold point to manage collisions - // btPersistentManifold* manifold = dynamicsWorld->getDispatcher()->getNewManifold(p_body->getBtBody(), btRigid); - // btManifoldPoint manifoldPoint(result_callabck.m_pointWorld, result_callabck.m_pointWorld, result_callabck.m_pointNormalWorld, result_callabck.m_penetration_distance); - // manifoldPoint.m_index0 = r_result->collision_local_shape; - // manifoldPoint.m_index1 = r_result->collider_shape; - // manifold->addManifoldPoint(manifoldPoint); - // p_body->get_kinematic_utilities()->m_generatedManifold.push_back(manifold); - //} - #if debug_test_motion Vector3 sup_line2; B_TO_G(motion, sup_line2); @@ -1022,7 +1002,7 @@ public: } }; -bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { +bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { RecoverPenetrationBroadPhaseCallback recover_broad_result(p_body->get_bt_collision_object(), p_body->get_collision_layer(), p_body->get_collision_mask()); @@ -1053,7 +1033,7 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran for (int i = recover_broad_result.result_collision_objects.size() - 1; 0 <= i; --i) { btCollisionObject *otherObject = recover_broad_result.result_collision_objects[i]; - if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object())) + if (!p_body->get_bt_collision_object()->checkCollideWith(otherObject) || !otherObject->checkCollideWith(p_body->get_bt_collision_object()) || (p_infinite_inertia && !otherObject->isStaticOrKinematicObject())) continue; if (otherObject->getCollisionShape()->isCompound()) { diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 2b97f0b274..a6c2786878 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -172,7 +172,7 @@ public: void update_gravity(); - bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, PhysicsServer::MotionResult *r_result); + bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result); private: void create_empty_world(bool p_create_soft_world); @@ -199,7 +199,7 @@ private: local_shape_most_recovered(0) {} }; - bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); + bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); /// This is an API that recover a kinematic object from penetration /// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = NULL); diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index df0985f6ac..69040a3df8 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -230,11 +230,12 @@ String GDMonoMethod::get_signature_desc(bool p_namespaces) const { } void GDMonoMethod::get_parameter_names(Vector<StringName> &names) const { - const char *_names[params_count]; - mono_method_get_param_names(mono_method, _names); + const char *_names = memnew_arr(char, params_count); + mono_method_get_param_names(mono_method, &_names); for (int i = 0; i < params_count; ++i) { - names.push_back(StringName(_names[i])); + names.push_back(StringName(&_names[i])); } + memdelete_arr(_names); } void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const { diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 9908907ee9..feb11089d0 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -30,6 +30,7 @@ #include "physics_body_2d.h" +#include "core/method_bind_ext.gen.inc" #include "engine.h" #include "scene/scene_string_names.h" @@ -362,12 +363,12 @@ struct _RigidBody2DInOut { int local_shape; }; -bool RigidBody2D::_test_motion(const Vector2 &p_motion, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) { +bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) { Physics2DServer::MotionResult *r = NULL; if (p_result.is_valid()) r = p_result->get_result_ptr(); - return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_margin, r); + return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r); } void RigidBody2D::_direct_state_changed(Object *p_state) { @@ -886,7 +887,7 @@ void RigidBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep); - ClassDB::bind_method(D_METHOD("test_motion", "motion", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(0.08), DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("test_motion", "motion", "infinite_inertia", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(true), DEFVAL(0.08), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody2D::_direct_state_changed); ClassDB::bind_method(D_METHOD("_body_enter_tree"), &RigidBody2D::_body_enter_tree); @@ -970,11 +971,11 @@ RigidBody2D::~RigidBody2D() { ////////////////////////// -Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion) { +Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia) { Collision col; - if (move_and_collide(p_motion, col)) { + if (move_and_collide(p_motion, p_infinite_inertia, col)) { if (motion_cache.is_null()) { motion_cache.instance(); motion_cache->owner = this; @@ -988,11 +989,11 @@ Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion) { return Ref<KinematicCollision2D>(); } -bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, Collision &r_collision) { +bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision) { Transform2D gt = get_global_transform(); Physics2DServer::MotionResult result; - bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result); + bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result); if (colliding) { r_collision.collider_metadata = result.collider_metadata; @@ -1012,7 +1013,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, Collision &r_col return colliding; } -Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { +Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { Vector2 motion = (floor_velocity + p_linear_velocity) * get_physics_process_delta_time(); Vector2 lv = p_linear_velocity; @@ -1027,7 +1028,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Collision collision; - bool collided = move_and_collide(motion, collision); + bool collided = move_and_collide(motion, p_infinite_inertia, collision); if (collided) { @@ -1094,11 +1095,11 @@ Vector2 KinematicBody2D::get_floor_velocity() const { return floor_velocity; } -bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion) { +bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia) { ERR_FAIL_COND_V(!is_inside_tree(), false); - return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, margin); + return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin); } void KinematicBody2D::set_safe_margin(float p_margin) { @@ -1139,10 +1140,10 @@ Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) { void KinematicBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec"), &KinematicBody2D::_move); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); + ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody2D::_move, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody2D::test_move); + ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move); ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index c755f30f2b..0fda3c5c05 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -185,7 +185,7 @@ private: void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape); void _direct_state_changed(Object *p_state); - bool _test_motion(const Vector2 &p_motion, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>()); + bool _test_motion(const Vector2 &p_motion, bool p_infinite_inertia = true, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>()); protected: void _notification(int p_what); @@ -296,20 +296,20 @@ private: _FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const; - Ref<KinematicCollision2D> _move(const Vector2 &p_motion); + Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true); Ref<KinematicCollision2D> _get_slide_collision(int p_bounce); protected: static void _bind_methods(); public: - bool move_and_collide(const Vector2 &p_motion, Collision &r_collision); - bool test_move(const Transform2D &p_from, const Vector2 &p_motion); + bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision); + bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia); void set_safe_margin(float p_margin); float get_safe_margin() const; - Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), float p_slope_stop_min_velocity = 5, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45)); + Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 5, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45)); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 361d765c97..2aa55e2825 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -353,7 +353,7 @@ void TileMap::_update_dirty_quadrants() { } Rect2 r = tile_set->tile_get_region(c.id); - if (tile_set->tile_get_is_autotile(c.id)) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) { int spacing = tile_set->autotile_get_spacing(c.id); r.size = tile_set->autotile_get_size(c.id); r.position += (r.size + Vector2(spacing, spacing)) * Vector2(c.autotile_coord_x, c.autotile_coord_y); @@ -447,7 +447,7 @@ void TileMap::_update_dirty_quadrants() { for (int i = 0; i < shapes.size(); i++) { Ref<Shape2D> shape = shapes[i].shape; if (shape.is_valid()) { - if (!tile_set->tile_get_is_autotile(c.id) || (shapes[i].autotile_coord.x == c.autotile_coord_x && shapes[i].autotile_coord.y == c.autotile_coord_y)) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::SINGLE_TILE || (shapes[i].autotile_coord.x == c.autotile_coord_x && shapes[i].autotile_coord.y == c.autotile_coord_y)) { Transform2D xform; xform.set_origin(offset.floor()); @@ -474,7 +474,7 @@ void TileMap::_update_dirty_quadrants() { if (navigation) { Ref<NavigationPolygon> navpoly; Vector2 npoly_ofs; - if (tile_set->tile_get_is_autotile(c.id)) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) { navpoly = tile_set->autotile_get_navigation_polygon(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); npoly_ofs = Vector2(); } else { @@ -497,7 +497,7 @@ void TileMap::_update_dirty_quadrants() { } Ref<OccluderPolygon2D> occluder; - if (tile_set->tile_get_is_autotile(c.id)) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) { occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); } else { occluder = tile_set->tile_get_light_occluder(c.id); @@ -766,7 +766,7 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) { Map<PosKey, Cell>::Element *E = tile_map.find(p); if (E != NULL) { int id = get_cell(p_x, p_y); - if (tile_set->tile_get_is_autotile(id)) { + if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) { uint16_t mask = 0; if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_2X2) { if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index ad94c19c31..ff4a807de0 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -928,10 +928,10 @@ RigidBody::~RigidBody() { ////////////////////////////////////////////////////// ////////////////////////// -Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion) { +Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia) { Collision col; - if (move_and_collide(p_motion, col)) { + if (move_and_collide(p_motion, p_infinite_inertia, col)) { if (motion_cache.is_null()) { motion_cache.instance(); motion_cache->owner = this; @@ -945,11 +945,11 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion) { return Ref<KinematicCollision>(); } -bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_collision) { +bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision) { Transform gt = get_global_transform(); PhysicsServer::MotionResult result; - bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, &result); + bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result); if (colliding) { r_collision.collider_metadata = result.collider_metadata; @@ -975,7 +975,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_colli return colliding; } -Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { +Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { Vector3 lv = p_linear_velocity; @@ -997,7 +997,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve Collision collision; - bool collided = move_and_collide(motion, collision); + bool collided = move_and_collide(motion, p_infinite_inertia, collision); if (collided) { @@ -1070,11 +1070,11 @@ Vector3 KinematicBody::get_floor_velocity() const { return floor_velocity; } -bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion) { +bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) { ERR_FAIL_COND_V(!is_inside_tree(), false); - return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion); + return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia); } void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) { @@ -1123,10 +1123,10 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) { void KinematicBody::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec"), &KinematicBody::_move); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_slides", "floor_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); + ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody::_move, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_slides", "floor_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(true), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody::test_move); + ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move); ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody::is_on_ceiling); diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 7899661d7f..ffdc9ab309 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -286,15 +286,15 @@ private: _FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const; - Ref<KinematicCollision> _move(const Vector3 &p_motion); + Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true); Ref<KinematicCollision> _get_slide_collision(int p_bounce); protected: static void _bind_methods(); public: - bool move_and_collide(const Vector3 &p_motion, Collision &r_collision); - bool test_move(const Transform &p_from, const Vector3 &p_motion); + bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision); + bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia); void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const; @@ -302,7 +302,7 @@ public: void set_safe_margin(float p_margin); float get_safe_margin() const; - Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), float p_slope_stop_min_velocity = 0.05, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45)); + Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 0.05, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45)); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 0312e58094..6e85ce5eb4 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -474,21 +474,24 @@ void TabContainer::remove_child_notify(Node *p_child) { Control::remove_child_notify(p_child); - int tc = get_tab_count(); - if (current == tc - 1) { - current--; - if (current < 0) - current = 0; - else { - call_deferred("set_current_tab", current); - } - } + call_deferred("_update_current_tab"); p_child->disconnect("renamed", this, "_child_renamed_callback"); update(); } +void TabContainer::_update_current_tab() { + + int tc = get_tab_count(); + if (current >= tc) + current = tc - 1; + if (current < 0) + current = 0; + else + set_current_tab(current); +} + void TabContainer::set_tab_align(TabAlign p_align) { ERR_FAIL_INDEX(p_align, 3); @@ -664,6 +667,7 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback); ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed); + ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab); ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab"))); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 0ba8c205ea..4bc6e00145 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -62,6 +62,7 @@ private: Vector<Control *> _get_tabs() const; int _get_tab_width(int p_index) const; void _on_theme_changed(); + void _update_current_tab(); protected: void _child_renamed_callback(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 8a1978cf85..ceac65ffa7 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -737,15 +737,18 @@ void SpatialMaterial::_update_shader() { } } - if (features[FEATURE_REFRACTION] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //refraction not supported with triplanar + if (features[FEATURE_REFRACTION]) { if (features[FEATURE_NORMAL_MAPPING]) { code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) );\n"; } else { code += "\tvec3 ref_normal = NORMAL;\n"; } - - code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n"; + if (flags[FLAG_UV1_USE_TRIPLANAR]) { + code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(triplanar_texture(texture_refraction,uv1_power_normal,uv1_triplanar_pos),refraction_texture_channel) * refraction;\n"; + } else { + code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n"; + } code += "\tfloat ref_amount = 1.0 - albedo.a * albedo_tex.a;\n"; code += "\tEMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n"; code += "\tALBEDO *= 1.0 - ref_amount;\n"; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 3138d73caf..4463f98b07 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -57,8 +57,8 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_modulate(id, p_value); else if (what == "region") tile_set_region(id, p_value); - else if (what == "is_autotile") - tile_set_is_autotile(id, p_value); + else if (what == "tile_mode") + tile_set_tile_mode(id, (TileMode)((int)p_value)); else if (what.left(9) == "autotile/") { what = what.right(9); if (what == "bitmask_mode") @@ -174,8 +174,8 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = tile_get_modulate(id); else if (what == "region") r_ret = tile_get_region(id); - else if (what == "is_autotile") - r_ret = tile_get_is_autotile(id); + else if (what == "tile_mode") + r_ret = tile_get_tile_mode(id); else if (what.left(9) == "autotile/") { what = what.right(9); if (what == "bitmask_mode") @@ -258,13 +258,13 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial")); p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate")); p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region")); - p_list->push_back(PropertyInfo(Variant::BOOL, pre + "is_autotile", PROPERTY_HINT_NONE, "")); - if (tile_get_is_autotile(id)) { + p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE")); + if (tile_get_tile_mode(id) == AUTO_TILE) { p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); @@ -282,7 +282,6 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { } void TileSet::create_tile(int p_id) { - ERR_FAIL_COND(tile_map.has(p_id)); tile_map[p_id] = TileData(); tile_map[p_id].autotile_data = AutotileData(); @@ -291,7 +290,6 @@ void TileSet::create_tile(int p_id) { } void TileSet::autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode) { - ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].autotile_data.bitmask_mode = p_mode; _change_notify(""); @@ -375,6 +373,7 @@ void TileSet::tile_set_region(int p_id, const Rect2 &p_region) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].region = p_region; emit_changed(); + _change_notify("region"); } Rect2 TileSet::tile_get_region(int p_id) const { @@ -383,18 +382,17 @@ Rect2 TileSet::tile_get_region(int p_id) const { return tile_map[p_id].region; } -void TileSet::tile_set_is_autotile(int p_id, bool p_is_autotile) { - +void TileSet::tile_set_tile_mode(int p_id, TileMode p_tile_mode) { ERR_FAIL_COND(!tile_map.has(p_id)); - tile_map[p_id].is_autotile = p_is_autotile; + tile_map[p_id].tile_mode = p_tile_mode; emit_changed(); - _change_notify("is_autotile"); + _change_notify("tile_mode"); } -bool TileSet::tile_get_is_autotile(int p_id) const { +TileSet::TileMode TileSet::tile_get_tile_mode(int p_id) const { - ERR_FAIL_COND_V(!tile_map.has(p_id), false); - return tile_map[p_id].is_autotile; + ERR_FAIL_COND_V(!tile_map.has(p_id), SINGLE_TILE); + return tile_map[p_id].tile_mode; } void TileSet::autotile_set_icon_coordinate(int p_id, Vector2 coord) { @@ -534,6 +532,7 @@ void TileSet::tile_set_name(int p_id, const String &p_name) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].name = p_name; emit_changed(); + _change_notify("name"); } String TileSet::tile_get_name(int p_id) const { diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 1306e2878c..46f34b6252 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -71,6 +71,12 @@ public: BIND_BOTTOMRIGHT = 256 }; + enum TileMode { + SINGLE_TILE, + AUTO_TILE, + ANIMATED_TILE + }; + struct AutotileData { BitmaskMode bitmask_mode; int spacing; @@ -84,6 +90,7 @@ public: // Default size to prevent invalid value explicit AutotileData() : size(64, 64), + spacing(0), icon_coord(0, 0) { bitmask_mode = BITMASK_2X2; } @@ -104,13 +111,13 @@ private: Ref<NavigationPolygon> navigation_polygon; Ref<ShaderMaterial> material; Color modulate; - bool is_autotile; + TileMode tile_mode; AutotileData autotile_data; // Default modulate for back-compat explicit TileData() : - modulate(1, 1, 1), - is_autotile(false) {} + tile_mode(SINGLE_TILE), + modulate(1, 1, 1) {} }; Map<int, TileData> tile_map; @@ -146,8 +153,8 @@ public: void tile_set_region(int p_id, const Rect2 &p_region); Rect2 tile_get_region(int p_id) const; - void tile_set_is_autotile(int p_id, bool p_is_autotile); - bool tile_get_is_autotile(int p_id) const; + void tile_set_tile_mode(int p_id, TileMode p_tile_mode); + TileMode tile_get_tile_mode(int p_id) const; void autotile_set_icon_coordinate(int p_id, Vector2 coord); Vector2 autotile_get_icon_coordinate(int p_id) const; diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 0f7c6deaac..f2dbb635f8 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -902,7 +902,7 @@ bool PhysicsServerSW::body_is_ray_pickable(RID p_body) const { return body->is_ray_pickable(); } -bool PhysicsServerSW::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, MotionResult *r_result) { +bool PhysicsServerSW::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result) { BodySW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body, false); @@ -911,7 +911,7 @@ bool PhysicsServerSW::body_test_motion(RID p_body, const Transform &p_from, cons _update_shapes(); - return body->get_space()->test_body_motion(body, p_from, p_motion, body->get_kinematic_margin(), r_result); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, body->get_kinematic_margin(), r_result); } PhysicsDirectBodyState *PhysicsServerSW::body_get_direct_state(RID p_body) { diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 923b59d28f..3f56ba26d0 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -225,7 +225,7 @@ public: virtual void body_set_ray_pickable(RID p_body, bool p_enable); virtual bool body_is_ray_pickable(RID p_body) const; - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, MotionResult *r_result = NULL); + virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL); // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body); diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index fe6c42a531..b604e5cdf6 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -541,7 +541,7 @@ int SpaceSW::_cull_aabb_for_body(BodySW *p_body, const AABB &p_aabb) { return amount; } -bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer::MotionResult *r_result) { +bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result) { //give me back regular physics engine logic //this is madness diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h index 0d519ea50b..2452d6a187 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -197,7 +197,7 @@ public: void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; } uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; } - bool test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer::MotionResult *r_result); + bool test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result); SpaceSW(); ~SpaceSW(); diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 0603287a79..a14fed8184 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -962,14 +962,14 @@ void Physics2DServerSW::body_set_pickable(RID p_body, bool p_pickable) { body->set_pickable(p_pickable); } -bool Physics2DServerSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, MotionResult *r_result) { +bool Physics2DServerSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result) { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); ERR_FAIL_COND_V(body->get_space()->is_locked(), false); - return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result); } Physics2DDirectBodyState *Physics2DServerSW::body_get_direct_state(RID p_body) { diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index cf9c2957bf..036eb934e1 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -232,7 +232,7 @@ public: virtual void body_set_pickable(RID p_body, bool p_pickable); - virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = NULL); + virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = NULL); // this function only works on physics process, errors and returns null otherwise virtual Physics2DDirectBodyState *body_get_direct_state(RID p_body); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index d625bc9892..a15e8bde8b 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -245,10 +245,10 @@ public: FUNC2(body_set_pickable, RID, bool); - bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = NULL) { + bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = NULL) { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); - return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result); + return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result); } // this function only works on physics process, errors and returns null otherwise diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index d3b81c627a..c29093d1af 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -483,7 +483,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) { return amount; } -bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, Physics2DServer::MotionResult *r_result) { +bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, Physics2DServer::MotionResult *r_result) { //give me back regular physics engine logic //this is madness @@ -550,6 +550,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co const CollisionObject2DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; + if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) { + const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) { + continue; + } + } + if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); @@ -638,6 +645,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co int col_shape_idx = intersection_query_subindex_results[i]; Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx); + if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) { + const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) { + continue; + } + } + bool excluded = false; for (int k = 0; k < excluded_shape_pair_count; k++) { @@ -768,6 +782,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co const CollisionObject2DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; + if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) { + const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) { + continue; + } + } + Shape2DSW *against_shape = col_obj->get_shape(shape_idx); bool excluded = false; diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index a18bb2be2d..79349c46f3 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -182,7 +182,7 @@ public: int get_collision_pairs() const { return collision_pairs; } - bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, Physics2DServer::MotionResult *r_result); + bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, Physics2DServer::MotionResult *r_result); void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index 5f08cd9243..fafc239c7f 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "physics_2d_server.h" +#include "core/method_bind_ext.gen.inc" #include "core/project_settings.h" #include "print_string.h" @@ -476,12 +477,12 @@ Physics2DTestMotionResult::Physics2DTestMotionResult() { /////////////////////////////////////// -bool Physics2DServer::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) { +bool Physics2DServer::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) { MotionResult *r = NULL; if (p_result.is_valid()) r = p_result->get_result_ptr(); - return body_test_motion(p_body, p_from, p_motion, p_margin, r); + return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r); } void Physics2DServer::_bind_methods() { @@ -598,7 +599,7 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &Physics2DServer::body_set_force_integration_callback, DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "margin", "result"), &Physics2DServer::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &Physics2DServer::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &Physics2DServer::body_get_direct_state); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 462244c667..ba5232f7fe 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -217,7 +217,7 @@ class Physics2DServer : public Object { static Physics2DServer *singleton; - virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>()); + virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>()); protected: static void _bind_methods(); @@ -479,7 +479,7 @@ public: Variant collider_metadata; }; - virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, float p_margin = 0.001, MotionResult *r_result = NULL) = 0; + virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.001, MotionResult *r_result = NULL) = 0; /* JOINT API */ diff --git a/servers/physics_server.h b/servers/physics_server.h index c21aa32f6c..6a342b36d4 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -474,7 +474,7 @@ public: Variant collider_metadata; }; - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, MotionResult *r_result = NULL) = 0; + virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL) = 0; /* JOINT API */ |