diff options
60 files changed, 854 insertions, 344 deletions
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp index b41f74a4bc..ff09b0b86c 100644 --- a/core/extension/gdnative_interface.cpp +++ b/core/extension/gdnative_interface.cpp @@ -854,14 +854,21 @@ static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_clas return (GDNativeMethodBindPtr)mb; } -static GDNativeClassConstructor gdnative_classdb_get_constructor(const char *p_classname) { +static GDNativeClassConstructor gdnative_classdb_get_constructor(const char *p_classname, GDNativeExtensionPtr *r_extension) { ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname)); if (class_info) { + if (r_extension) { + *r_extension = class_info->native_extension; + } return (GDNativeClassConstructor)class_info->creation_func; } return nullptr; } +static GDNativeObjectPtr gdnative_classdb_construct_object(GDNativeClassConstructor p_constructor, GDNativeExtensionPtr p_extension) { + return (GDNativeObjectPtr)ClassDB::construct_object((Object * (*)()) p_constructor, (ObjectNativeExtension *)p_extension); +} + static void *gdnative_classdb_get_class_tag(const char *p_classname) { ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(p_classname); return class_info ? class_info->class_ptr : nullptr; @@ -1010,6 +1017,7 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) { /* CLASSDB */ gdni.classdb_get_constructor = gdnative_classdb_get_constructor; + gdni.classdb_construct_object = gdnative_classdb_construct_object; gdni.classdb_get_method_bind = gdnative_classdb_get_method_bind; gdni.classdb_get_class_tag = gdnative_classdb_get_class_tag; diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h index df735db9b6..73f78bde54 100644 --- a/core/extension/gdnative_interface.h +++ b/core/extension/gdnative_interface.h @@ -137,6 +137,7 @@ typedef void *GDNativeStringNamePtr; typedef void *GDNativeStringPtr; typedef void *GDNativeObjectPtr; typedef void *GDNativeTypePtr; +typedef void *GDNativeExtensionPtr; typedef void *GDNativeMethodBindPtr; typedef int64_t GDNativeInt; typedef uint8_t GDNativeBool; @@ -431,7 +432,8 @@ typedef struct { /* CLASSDB */ - GDNativeClassConstructor (*classdb_get_constructor)(const char *p_classname); + GDNativeClassConstructor (*classdb_get_constructor)(const char *p_classname, GDNativeExtensionPtr *r_extension); + GDNativeObjectPtr (*classdb_construct_object)(GDNativeClassConstructor p_constructor, GDNativeExtensionPtr p_extension); GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash); void *(*classdb_get_class_tag)(const char *p_classname); diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index 33aa65f15d..51a1309f0e 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -52,8 +52,8 @@ void AABB::merge_with(const AABB &p_aabb) { beg_1 = position; beg_2 = p_aabb.position; - end_1 = Vector3(size.x, size.y, size.z) + beg_1; - end_2 = Vector3(p_aabb.size.x, p_aabb.size.y, p_aabb.size.z) + beg_2; + end_1 = size + beg_1; + end_2 = p_aabb.size + beg_2; min.x = (beg_1.x < beg_2.x) ? beg_1.x : beg_2.x; min.y = (beg_1.y < beg_2.y) ? beg_1.y : beg_2.y; diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 8e92340c1e..8ba46e49eb 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -545,6 +545,15 @@ Object *ClassDB::instantiate(const StringName &p_class) { return ti->creation_func(); } +Object *ClassDB::construct_object(Object *(*p_create_func)(), ObjectNativeExtension *p_extension) { + if (p_extension) { + initializing_with_extension = true; + initializing_extension = p_extension; + initializing_extension_instance = p_extension->create_instance(p_extension->class_userdata); + } + return p_create_func(); +} + bool ClassDB::can_instantiate(const StringName &p_class) { OBJTYPE_RLOCK; diff --git a/core/object/class_db.h b/core/object/class_db.h index e89c7fffd7..3a1cbf8559 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -234,6 +234,7 @@ public: static bool is_parent_class(const StringName &p_class, const StringName &p_inherits); static bool can_instantiate(const StringName &p_class); static Object *instantiate(const StringName &p_class); + static Object *construct_object(Object *(*p_create_func)(), ObjectNativeExtension *p_extension); static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance, Object *p_base); static APIType get_api_type(const StringName &p_class); diff --git a/core/templates/pooled_list.h b/core/templates/pooled_list.h index b4a6d2d1dd..b139dadb75 100644 --- a/core/templates/pooled_list.h +++ b/core/templates/pooled_list.h @@ -28,13 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#pragma once +#ifndef POOLED_LIST_H +#define POOLED_LIST_H + +#include "core/templates/local_vector.h" // Simple template to provide a pool with O(1) allocate and free. // The freelist could alternatively be a linked list placed within the unused elements // to use less memory, however a separate freelist is probably more cache friendly. - -// NOTE : Take great care when using this with non POD types. The construction and destruction +// +// NOTE: Take great care when using this with non POD types. The construction and destruction // is done in the LocalVector, NOT as part of the pool. So requesting a new item does not guarantee // a constructor is run, and free does not guarantee a destructor. // You should generally handle clearing @@ -42,9 +45,6 @@ // This is by design for fastest use in the BVH. If you want a more general pool // that does call constructors / destructors on request / free, this should probably be // a separate template. - -#include "core/templates/local_vector.h" - template <class T, bool force_trivial = false> class PooledList { LocalVector<T, uint32_t, force_trivial> list; @@ -93,3 +93,5 @@ public: _used_size--; } }; + +#endif // POOLED_LIST_H diff --git a/doc/classes/TileSetAtlasSource.xml b/doc/classes/TileSetAtlasSource.xml index 75f7d19b31..d12ac840f4 100644 --- a/doc/classes/TileSetAtlasSource.xml +++ b/doc/classes/TileSetAtlasSource.xml @@ -15,16 +15,6 @@ <tutorials> </tutorials> <methods> - <method name="can_move_tile_in_atlas" qualifiers="const"> - <return type="bool" /> - <argument index="0" name="atlas_coords" type="Vector2i" /> - <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" /> - <argument index="2" name="new_size" type="Vector2i" default="Vector2i(-1, -1)" /> - <description> - Returns true if the tile at the [code]atlas_coords[/code] coordinates can be moved to the [code]new_atlas_coords[/code] coordinates with the [code]new_size[/code] size. This functions returns false if a tile is already present in the given area, or if this area is outside the atlas boundaries. - If [code]new_atlas_coords[/code] is [code]Vector2i(-1, -1)[/code], keeps the tile's coordinates. If [code]new_size[/code] is [code]Vector2i(-1, -1)[/code], keeps the tile's size. - </description> - </method> <method name="clear_tiles_outside_texture"> <return type="void" /> <description> @@ -61,6 +51,49 @@ Returns the alternative ID a following call to [method create_alternative_tile] would return. </description> </method> + <method name="get_tile_animation_columns" qualifiers="const"> + <return type="int" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <description> + Returns how many columns the tile at [code]atlas_coords[/code] has in its animation layout. + </description> + </method> + <method name="get_tile_animation_frame_duration" qualifiers="const"> + <return type="float" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="frame_index" type="int" /> + <description> + Returns the animation frame duration of frame [code]frame_index[/code] for the tile at coordinates [code]atlas_coords[/code]. + </description> + </method> + <method name="get_tile_animation_frames_count" qualifiers="const"> + <return type="int" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <description> + Returns how many animation frames has the tile at coordinates [code]atlas_coords[/code]. + </description> + </method> + <method name="get_tile_animation_separation" qualifiers="const"> + <return type="Vector2i" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <description> + Returns the separation (as in the atlas grid) between each frame of an animated tile at coordinates [code]atlas_coords[/code]. + </description> + </method> + <method name="get_tile_animation_speed" qualifiers="const"> + <return type="float" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <description> + Returns the animation speed of the tile at coordinates [code]atlas_coords[/code]. + </description> + </method> + <method name="get_tile_animation_total_duration" qualifiers="const"> + <return type="float" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <description> + Returns the sum of the sum of the frame durations of the tile at coordinates [code]atlas_coords[/code]. This value needs to be divided by the animation speed to get the actual animation loop duration. + </description> + </method> <method name="get_tile_at_coords" qualifiers="const"> <return type="Vector2i" /> <argument index="0" name="atlas_coords" type="Vector2i" /> @@ -86,8 +119,21 @@ <method name="get_tile_texture_region" qualifiers="const"> <return type="Rect2i" /> <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="frame" type="int" default="0" /> + <description> + Returns a tile's texture region in the atlas texture. For animated tiles, a [code]frame[/code] argument might be provided for the different frames of the animation. + </description> + </method> + <method name="has_room_for_tile" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="size" type="Vector2i" /> + <argument index="2" name="animation_columns" type="int" /> + <argument index="3" name="animation_separation" type="Vector2i" /> + <argument index="4" name="frames_count" type="int" /> + <argument index="5" name="ignored_tile" type="Vector2i" default="Vector2i(-1, -1)" /> <description> - Returns a tile's texture region in the atlas texture. + Returns whether there is enough room in an atlas to create/modify a tile with the given properties. If [code]ignored_tile[/code] is provided, act as is the given tile was not present in the atlas. This may be used when you want to modify a tile's properties. </description> </method> <method name="has_tiles_outside_texture"> @@ -104,7 +150,7 @@ <description> Move the tile and its alternatives at the [code]atlas_coords[/code] coordinates to the [code]new_atlas_coords[/code] coordinates with the [code]new_size[/code] size. This functions will fail if a tile is already present in the given area. If [code]new_atlas_coords[/code] is [code]Vector2i(-1, -1)[/code], keeps the tile's coordinates. If [code]new_size[/code] is [code]Vector2i(-1, -1)[/code], keeps the tile's size. - To avoid an error, first check if a move is possible using [method can_move_tile_in_atlas]. + To avoid an error, first check if a move is possible using [method has_room_for_tile]. </description> </method> <method name="remove_alternative_tile"> @@ -133,6 +179,47 @@ Calling this function with [code]alternative_id[/code] equals to 0 will fail, as the base tile alternative cannot be moved. </description> </method> + <method name="set_tile_animation_columns"> + <return type="void" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="frame_columns" type="int" /> + <description> + Sets the number of columns in the animation layout of the tile at coordinates [code]atlas_coords[/code]. If set to 0, then the different frames of the animation are laid out as a single horizontal line in the atlas. + </description> + </method> + <method name="set_tile_animation_frame_duration"> + <return type="void" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="frame_index" type="int" /> + <argument index="2" name="duration" type="float" /> + <description> + Sets the animation frame duration of frame [code]frame_index[/code] for the tile at coordinates [code]atlas_coords[/code]. + </description> + </method> + <method name="set_tile_animation_frames_count"> + <return type="void" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="frames_count" type="int" /> + <description> + Sets how many animation frames the tile at coordinates [code]atlas_coords[/code] has. + </description> + </method> + <method name="set_tile_animation_separation"> + <return type="void" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="separation" type="Vector2i" /> + <description> + Sets the margin (in grid tiles) between each tile in the animation layout of the tile at coordinates [code]atlas_coords[/code] has. + </description> + </method> + <method name="set_tile_animation_speed"> + <return type="void" /> + <argument index="0" name="atlas_coords" type="Vector2i" /> + <argument index="1" name="speed" type="float" /> + <description> + Sets the animation speed of the tile at coordinates [code]atlas_coords[/code] has. + </description> + </method> </methods> <members> <member name="margins" type="Vector2i" setter="set_margins" getter="get_margins" default="Vector2i(0, 0)"> diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index fca69f34f3..28642f1bb4 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -491,10 +491,10 @@ void AnimationBezierTrackEdit::_notification(int p_what) { } draw_rect( Rect2(bs_from, bs_to - bs_from), - get_theme_color("box_selection_fill_color", "Editor")); + get_theme_color(SNAME("box_selection_fill_color"), SNAME("Editor"))); draw_rect( Rect2(bs_from, bs_to - bs_from), - get_theme_color("box_selection_stroke_color", "Editor"), + get_theme_color(SNAME("box_selection_stroke_color"), SNAME("Editor")), false, Math::round(EDSCALE)); } diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 989774e943..5fda1c76ef 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -397,15 +397,15 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da s->select(0); } } - emit_signal("stack_dump", stack_dump_info); + emit_signal(SNAME("stack_dump"), stack_dump_info); } else if (p_msg == "stack_frame_vars") { inspector->clear_stack_variables(); ERR_FAIL_COND(p_data.size() != 1); - emit_signal("stack_frame_vars", p_data[0]); + emit_signal(SNAME("stack_frame_vars"), p_data[0]); } else if (p_msg == "stack_frame_var") { inspector->add_stack_variable(p_data); - emit_signal("stack_frame_var", p_data); + emit_signal(SNAME("stack_frame_var"), p_data); } else if (p_msg == "output") { ERR_FAIL_COND(p_data.size() != 2); @@ -434,7 +434,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da } break; } EditorNode::get_log()->add_message(output_strings[i], msg_type); - emit_signal("output", output_strings[i]); + emit_signal(SNAME("output"), output_strings[i]); } } else if (p_msg == "performance:profile_frame") { Vector<float> frame_data; diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 88087664d7..b9f1c1af54 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -535,7 +535,7 @@ void EditorAudioBus::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) { - Vector2 pos = Vector2(mb->get_position().x, mb->get_position().y); + Vector2 pos = mb->get_position(); bus_popup->set_position(get_global_position() + pos); bus_popup->popup(); } diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index 4ad45f9649..e69ced8522 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -118,8 +118,8 @@ void EditorCommandPalette::_update_command_search(const String &search_text) { section->set_text(0, item_name); section->set_selectable(0, false); section->set_selectable(1, false); - section->set_custom_bg_color(0, search_options->get_theme_color("prop_subsection", "Editor")); - section->set_custom_bg_color(1, search_options->get_theme_color("prop_subsection", "Editor")); + section->set_custom_bg_color(0, search_options->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); + section->set_custom_bg_color(1, search_options->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); sections[section_name] = section; } @@ -263,7 +263,7 @@ Ref<Shortcut> EditorCommandPalette::add_shortcut_command(const String &p_command } void EditorCommandPalette::_theme_changed() { - command_search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons")); + command_search_box->set_right_icon(search_options->get_theme_icon(SNAME("Search"), SNAME("EditorIcons"))); } void EditorCommandPalette::_save_history() const { diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index bf95e6cf62..8956983646 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -86,7 +86,7 @@ void EditorFileDialog::_notification(int p_what) { if (preview_wheel_index >= 8) { preview_wheel_index = 0; } - Ref<Texture2D> frame = item_list->get_theme_icon("Progress" + itos(preview_wheel_index + 1), "EditorIcons"); + Ref<Texture2D> frame = item_list->get_theme_icon("Progress" + itos(preview_wheel_index + 1), SNAME("EditorIcons")); preview->set_texture(frame); preview_wheel_timeout = 0.1; } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ef8dabc19a..e719797e03 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -576,7 +576,7 @@ void EditorNode::_notification(int p_what) { // update the icon itself only when the spinner is visible if (EditorSettings::get_singleton()->get("interface/editor/show_update_spinner")) { - update_spinner->set_icon(gui_base->get_theme_icon("Progress" + itos(update_spinner_step + 1), "EditorIcons")); + update_spinner->set_icon(gui_base->get_theme_icon("Progress" + itos(update_spinner_step + 1), SNAME("EditorIcons"))); } } @@ -767,7 +767,7 @@ void EditorNode::_update_update_spinner() { // On a light theme, icons are dark, so we need to modulate them with an even brighter color. const bool dark_theme = EditorSettings::get_singleton()->is_dark_theme(); update_spinner->set_self_modulate( - gui_base->get_theme_color("error_color", "Editor") * (dark_theme ? Color(1.1, 1.1, 1.1) : Color(4.25, 4.25, 4.25))); + gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor")) * (dark_theme ? Color(1.1, 1.1, 1.1) : Color(4.25, 4.25, 4.25))); } else { update_spinner->set_tooltip(TTR("Spins when the editor window redraws.")); update_spinner->set_self_modulate(Color(1, 1, 1)); @@ -6105,9 +6105,9 @@ EditorNode::EditorNode() { dock_tab_move_right = memnew(Button); dock_tab_move_right->set_flat(true); if (gui_base->is_layout_rtl()) { - dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons")); - } else { dock_tab_move_right->set_icon(theme->get_icon("Back", "EditorIcons")); + } else { + dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons")); } dock_tab_move_right->set_focus_mode(Control::FOCUS_NONE); dock_tab_move_right->connect("pressed", callable_mp(this, &EditorNode::_dock_move_right)); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 6c0d11cc6b..c0dadc4484 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2951,8 +2951,8 @@ void EditorPropertyResource::_update_property_bg() { count_subinspectors = MIN(15, count_subinspectors); add_theme_color_override("property_color", get_theme_color(SNAME("sub_inspector_property_color"), SNAME("Editor"))); - add_theme_style_override("bg_selected", get_theme_stylebox("sub_inspector_property_bg_selected" + itos(count_subinspectors), "Editor")); - add_theme_style_override("bg", get_theme_stylebox("sub_inspector_property_bg" + itos(count_subinspectors), "Editor")); + add_theme_style_override("bg_selected", get_theme_stylebox("sub_inspector_property_bg_selected" + itos(count_subinspectors), SNAME("Editor"))); + add_theme_style_override("bg", get_theme_stylebox("sub_inspector_property_bg" + itos(count_subinspectors), SNAME("Editor"))); add_theme_constant_override("font_offset", get_theme_constant(SNAME("sub_inspector_font_offset"), SNAME("Editor"))); add_theme_constant_override("vseparation", 0); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index c98fbea530..9dbf69a779 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -924,7 +924,7 @@ void EditorShaderPicker::set_create_options(Object *p_menu_node) { return; } - menu_node->add_icon_item(get_theme_icon("Shader", "EditorIcons"), TTR("New Shader"), OBJ_MENU_NEW_SHADER); + menu_node->add_icon_item(get_theme_icon(SNAME("Shader"), SNAME("EditorIcons")), TTR("New Shader"), OBJ_MENU_NEW_SHADER); menu_node->add_separator(); } diff --git a/editor/import/dynamicfont_import_settings.cpp b/editor/import/dynamicfont_import_settings.cpp index 37ca40287f..9a8abfa5c6 100644 --- a/editor/import/dynamicfont_import_settings.cpp +++ b/editor/import/dynamicfont_import_settings.cpp @@ -92,6 +92,8 @@ struct UniRange { String name; }; +// Unicode Character Blocks +// Source: https://www.unicode.org/Public/14.0.0/ucd/Blocks.txt static UniRange unicode_ranges[] = { { 0x0000, 0x007F, U"Basic Latin" }, { 0x0080, 0x00FF, U"Latin-1 Supplement" }, @@ -109,10 +111,11 @@ static UniRange unicode_ranges[] = { { 0x0700, 0x074F, U"Syriac" }, { 0x0750, 0x077F, U"Arabic Supplement" }, { 0x0780, 0x07BF, U"Thaana" }, - { 0x07C0, 0x07FF, U"N'Ko" }, + { 0x07C0, 0x07FF, U"NKo" }, { 0x0800, 0x083F, U"Samaritan" }, { 0x0840, 0x085F, U"Mandaic" }, { 0x0860, 0x086F, U"Syriac Supplement" }, + { 0x0870, 0x089F, U"Arabic Extended-B" }, { 0x08A0, 0x08FF, U"Arabic Extended-A" }, { 0x0900, 0x097F, U"Devanagari" }, { 0x0980, 0x09FF, U"Bengali" }, @@ -239,9 +242,12 @@ static UniRange unicode_ranges[] = { { 0xAB30, 0xAB6F, U"Latin Extended-E" }, { 0xAB70, 0xABBF, U"Cherokee Supplement" }, { 0xABC0, 0xABFF, U"Meetei Mayek" }, + { 0xAC00, 0xD7AF, U"Hangul Syllables" }, { 0xD7B0, 0xD7FF, U"Hangul Jamo Extended-B" }, - //{ 0xF800, 0xDFFF, U"Surrogates" }, - { 0xE000, 0xE2FE, U"Private Use Area" }, + //{ 0xD800, 0xDB7F, U"High Surrogates" }, + //{ 0xDB80, 0xDBFF, U"High Private Use Surrogates" }, + //{ 0xDC00, 0xDFFF, U"Low Surrogates" }, + { 0xE000, 0xF8FF, U"Private Use Area" }, { 0xF900, 0xFAFF, U"CJK Compatibility Ideographs" }, { 0xFB00, 0xFB4F, U"Alphabetic Presentation Forms" }, { 0xFB50, 0xFDFF, U"Arabic Presentation Forms-A" }, @@ -273,7 +279,9 @@ static UniRange unicode_ranges[] = { { 0x104B0, 0x104FF, U"Osage" }, { 0x10500, 0x1052F, U"Elbasan" }, { 0x10530, 0x1056F, U"Caucasian Albanian" }, + { 0x10570, 0x105BF, U"Vithkuqi" }, { 0x10600, 0x1077F, U"Linear A" }, + { 0x10780, 0x107BF, U"Latin Extended-F" }, { 0x10800, 0x1083F, U"Cypriot Syllabary" }, { 0x10840, 0x1085F, U"Imperial Aramaic" }, { 0x10860, 0x1087F, U"Palmyrene" }, @@ -298,6 +306,7 @@ static UniRange unicode_ranges[] = { { 0x10E80, 0x10EBF, U"Yezidi" }, { 0x10F00, 0x10F2F, U"Old Sogdian" }, { 0x10F30, 0x10F6F, U"Sogdian" }, + { 0x10F70, 0x10FAF, U"Old Uyghur" }, { 0x10FB0, 0x10FDF, U"Chorasmian" }, { 0x10FE0, 0x10FFF, U"Elymaic" }, { 0x11000, 0x1107F, U"Brahmi" }, @@ -317,13 +326,14 @@ static UniRange unicode_ranges[] = { { 0x11600, 0x1165F, U"Modi" }, { 0x11660, 0x1167F, U"Mongolian Supplement" }, { 0x11680, 0x116CF, U"Takri" }, - { 0x11700, 0x1173F, U"Ahom" }, + { 0x11700, 0x1174F, U"Ahom" }, { 0x11800, 0x1184F, U"Dogra" }, { 0x118A0, 0x118FF, U"Warang Citi" }, { 0x11900, 0x1195F, U"Dives Akuru" }, { 0x119A0, 0x119FF, U"Nandinagari" }, { 0x11A00, 0x11A4F, U"Zanabazar Square" }, { 0x11A50, 0x11AAF, U"Soyombo" }, + { 0x11AB0, 0x11ABF, U"Unified Canadian Aboriginal Syllabics Extended-A" }, { 0x11AC0, 0x11AFF, U"Pau Cin Hau" }, { 0x11C00, 0x11C6F, U"Bhaiksuki" }, { 0x11C70, 0x11CBF, U"Marchen" }, @@ -335,11 +345,13 @@ static UniRange unicode_ranges[] = { { 0x12000, 0x123FF, U"Cuneiform" }, { 0x12400, 0x1247F, U"Cuneiform Numbers and Punctuation" }, { 0x12480, 0x1254F, U"Early Dynastic Cuneiform" }, + { 0x12F90, 0x12FFF, U"Cypro-Minoan" }, { 0x13000, 0x1342F, U"Egyptian Hieroglyphs" }, { 0x13430, 0x1343F, U"Egyptian Hieroglyph Format Controls" }, { 0x14400, 0x1467F, U"Anatolian Hieroglyphs" }, { 0x16800, 0x16A3F, U"Bamum Supplement" }, { 0x16A40, 0x16A6F, U"Mro" }, + { 0x16A70, 0x16ACF, U"Tangsa" }, { 0x16AD0, 0x16AFF, U"Bassa Vah" }, { 0x16B00, 0x16B8F, U"Pahawh Hmong" }, { 0x16E40, 0x16E9F, U"Medefaidrin" }, @@ -348,13 +360,15 @@ static UniRange unicode_ranges[] = { { 0x17000, 0x187FF, U"Tangut" }, { 0x18800, 0x18AFF, U"Tangut Components" }, { 0x18B00, 0x18CFF, U"Khitan Small Script" }, - { 0x18D00, 0x18D8F, U"Tangut Supplement" }, + { 0x18D00, 0x18D7F, U"Tangut Supplement" }, + { 0x1AFF0, 0x1AFFF, U"Kana Extended-B" }, { 0x1B000, 0x1B0FF, U"Kana Supplement" }, { 0x1B100, 0x1B12F, U"Kana Extended-A" }, { 0x1B130, 0x1B16F, U"Small Kana Extension" }, { 0x1B170, 0x1B2FF, U"Nushu" }, { 0x1BC00, 0x1BC9F, U"Duployan" }, { 0x1BCA0, 0x1BCAF, U"Shorthand Format Controls" }, + { 0x1CF00, 0x1CFCF, U"Znamenny Musical Notation" }, { 0x1D000, 0x1D0FF, U"Byzantine Musical Symbols" }, { 0x1D100, 0x1D1FF, U"Musical Symbols" }, { 0x1D200, 0x1D24F, U"Ancient Greek Musical Notation" }, @@ -363,9 +377,12 @@ static UniRange unicode_ranges[] = { { 0x1D360, 0x1D37F, U"Counting Rod Numerals" }, { 0x1D400, 0x1D7FF, U"Mathematical Alphanumeric Symbols" }, { 0x1D800, 0x1DAAF, U"Sutton SignWriting" }, + { 0x1DF00, 0x1DFFF, U"Latin Extended-G" }, { 0x1E000, 0x1E02F, U"Glagolitic Supplement" }, { 0x1E100, 0x1E14F, U"Nyiakeng Puachue Hmong" }, + { 0x1E290, 0x1E2BF, U"Toto" }, { 0x1E2C0, 0x1E2FF, U"Wancho" }, + { 0x1E7E0, 0x1E7FF, U"Ethiopic Extended-B" }, { 0x1E800, 0x1E8DF, U"Mende Kikakui" }, { 0x1E900, 0x1E95F, U"Adlam" }, { 0x1EC70, 0x1ECBF, U"Indic Siyaq Numbers" }, @@ -396,8 +413,8 @@ static UniRange unicode_ranges[] = { { 0x30000, 0x3134F, U"CJK Unified Ideographs Extension G" }, //{ 0xE0000, 0xE007F, U"Tags" }, //{ 0xE0100, 0xE01EF, U"Variation Selectors Supplement" }, - { 0xF0000, 0xFFFFD, U"Supplementary Private Use Area-A" }, - { 0x100000, 0x10FFFD, U"Supplementary Private Use Area-B" }, + { 0xF0000, 0xFFFFF, U"Supplementary Private Use Area-A" }, + { 0x100000, 0x10FFFF, U"Supplementary Private Use Area-B" }, { 0x10FFFF, 0x10FFFF, String() } }; @@ -1799,7 +1816,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { glyph_tree = memnew(Tree); glyphs_split->add_child(glyph_tree); glyph_tree->set_custom_minimum_size(Size2(300 * EDSCALE, 0)); - glyph_tree->set_columns(3); + glyph_tree->set_columns(2); glyph_tree->set_hide_root(true); glyph_tree->set_column_expand(0, false); glyph_tree->set_column_expand(1, true); diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp index 869af209d3..36fd161c35 100644 --- a/editor/import/resource_importer_texture_atlas.cpp +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -324,7 +324,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file atlas_texture.instantiate(); atlas_texture->set_atlas(cache); atlas_texture->set_region(Rect2(offset, pack_data.region.size)); - atlas_texture->set_margin(Rect2(pack_data.region.position, Size2(pack_data.image->get_width(), pack_data.image->get_height()) - pack_data.region.size)); + atlas_texture->set_margin(Rect2(pack_data.region.position, pack_data.image->get_size() - pack_data.region.size)); texture = atlas_texture; } else { diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 648e60a554..5b52554335 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -127,12 +127,7 @@ void ImportDock::set_edit_path(const String &p_path) { } } - import_as->add_separator(); - import_as->add_item(TTR("Keep File (No Import)")); - import_as->set_item_metadata(import_as->get_item_count() - 1, "keep"); - if (importer_name == "keep") { - import_as->select(import_as->get_item_count() - 1); - } + _add_keep_import_option(importer_name); import->set_disabled(false); import_as->set_disabled(false); @@ -141,6 +136,15 @@ void ImportDock::set_edit_path(const String &p_path) { imported->set_text(p_path.get_file()); } +void ImportDock::_add_keep_import_option(const String &p_importer_name) { + import_as->add_separator(); + import_as->add_item(TTR("Keep File (No Import)")); + import_as->set_item_metadata(import_as->get_item_count() - 1, "keep"); + if (p_importer_name == "keep") { + import_as->select(import_as->get_item_count() - 1); + } +} + void ImportDock::_update_options(const Ref<ConfigFile> &p_config) { List<ResourceImporter::ImportOption> options; @@ -270,6 +274,8 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) { } } + _add_keep_import_option(params->importer->get_importer_name()); + _update_preset_menu(); params->paths = p_paths; diff --git a/editor/import_dock.h b/editor/import_dock.h index 2be48dd505..3c28bbcd89 100644 --- a/editor/import_dock.h +++ b/editor/import_dock.h @@ -66,6 +66,7 @@ class ImportDock : public VBoxContainer { void _importer_selected(int i_idx); void _update_options(const Ref<ConfigFile> &p_config = Ref<ConfigFile>()); void _update_preset_menu(); + void _add_keep_import_option(const String &p_importer_name); void _property_toggled(const StringName &p_prop, bool p_checked); void _reimport_attempt(); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 18b4966f80..68b143358a 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -120,7 +120,7 @@ void AnimationPlayerEditor::_notification(int p_what) { Ref<Image> autoplay_img = autoplay_icon->get_image(); Ref<Image> reset_img = reset_icon->get_image(); Ref<Image> autoplay_reset_img; - Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height()); + Size2 icon_size = autoplay_img->get_size(); autoplay_reset_img.instantiate(); autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format()); autoplay_reset_img->blit_rect(autoplay_img, Rect2(Point2(), icon_size), Point2()); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 04192efecd..1758ba7048 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3968,7 +3968,7 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { void CanvasItemEditor::_update_context_menu_stylebox() { // This must be called when the theme changes to follow the new accent color. Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat); - const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor"); + const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor")); context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1)); // Add an underline to the StyleBox, but prevent its minimum vertical size from changing. context_menu_stylebox->set_border_color(accent_color); diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 6f246c1661..fb9f8696fe 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -83,7 +83,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { } img->convert(Image::FORMAT_RGBA8); ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8); - Size2i s = Size2(img->get_width(), img->get_height()); + Size2i s = img->get_size(); ERR_FAIL_COND(s.width == 0 || s.height == 0); Vector<Point2> valid_positions; diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index dd91df747a..44c789b145 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -158,7 +158,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { } img->convert(Image::FORMAT_RGBA8); ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8); - Size2i s = Size2(img->get_width(), img->get_height()); + Size2i s = img->get_size(); ERR_FAIL_COND(s.width == 0 || s.height == 0); Vector<Point2> valid_positions; diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 231c5c4f72..d52a633fed 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -128,7 +128,7 @@ void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) { const Color axis_color = axis_colors[direction]; const double alpha = focused ? 1.0 : ((p_axis.z_axis + 1.0) / 2.0) * 0.5 + 0.5; - const Color c = focused ? Color(0.9, 0.9, 0.9) : Color(axis_color.r, axis_color.g, axis_color.b, alpha); + const Color c = focused ? Color(0.9, 0.9, 0.9) : Color(axis_color, alpha); if (positive) { // Draw axis lines for the positive axes. @@ -854,8 +854,8 @@ void Node3DEditorViewport::_update_name() { } void Node3DEditorViewport::_compute_edit(const Point2 &p_point) { - _edit.click_ray = _get_ray(Vector2(p_point.x, p_point.y)); - _edit.click_ray_pos = _get_ray_pos(Vector2(p_point.x, p_point.y)); + _edit.click_ray = _get_ray(p_point); + _edit.click_ray_pos = _get_ray_pos(p_point); _edit.plane = TRANSFORM_VIEW; spatial_editor->update_transform_gizmo(); _edit.center = spatial_editor->get_gizmo_transform().origin; @@ -934,8 +934,8 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b return false; } - Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y)); - Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y)); + Vector3 ray_pos = _get_ray_pos(p_screenpos); + Vector3 ray = _get_ray(p_screenpos); Transform3D gt = spatial_editor->get_gizmo_transform(); @@ -998,7 +998,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b } else { //handle plane translate _edit.mode = TRANSFORM_TRANSLATE; - _compute_edit(Point2(p_screenpos.x, p_screenpos.y)); + _compute_edit(p_screenpos); _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_translate ? 3 : 0)); } return true; @@ -1036,7 +1036,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b } else { //handle rotate _edit.mode = TRANSFORM_ROTATE; - _compute_edit(Point2(p_screenpos.x, p_screenpos.y)); + _compute_edit(p_screenpos); _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis); } return true; @@ -1102,7 +1102,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b } else { //handle scale _edit.mode = TRANSFORM_SCALE; - _compute_edit(Point2(p_screenpos.x, p_screenpos.y)); + _compute_edit(p_screenpos); _edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0)); } return true; @@ -6014,7 +6014,7 @@ void fragment() { void Node3DEditor::_update_context_menu_stylebox() { // This must be called when the theme changes to follow the new accent color. Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat); - const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor"); + const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor")); context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1)); // Add an underline to the StyleBox, but prevent its minimum vertical size from changing. context_menu_stylebox->set_border_color(accent_color); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 782152b002..ac18ff9f1c 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -449,7 +449,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (mb.is_valid()) { if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (mb->is_pressed()) { - uv_drag_from = snap_point(Vector2(mb->get_position().x, mb->get_position().y)); + uv_drag_from = snap_point(mb->get_position()); uv_drag = true; points_prev = node->get_uv(); @@ -463,7 +463,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { if (uv_move_current == UV_MODE_CREATE) { if (!uv_create) { points_prev.resize(0); - Vector2 tuv = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y))); + Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position())); points_prev.push_back(tuv); uv_create_to = tuv; point_drag_index = 0; @@ -483,7 +483,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_edit_draw->update(); } else { - Vector2 tuv = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y))); + Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position())); // Close the polygon if selected point is near start. Threshold for closing scaled by zoom level if (points_prev.size() > 2 && tuv.distance_to(points_prev[0]) < (8 / uv_draw_zoom)) { @@ -527,7 +527,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_create_bones_prev = node->call("_get_bones"); int internal_vertices = node->get_internal_vertex_count(); - Vector2 pos = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y))); + Vector2 pos = mtx.affine_inverse().xform(snap_point(mb->get_position())); uv_create_poly_prev.push_back(pos); uv_create_uv_prev.push_back(pos); @@ -573,7 +573,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { for (int i = points_prev.size() - internal_vertices; i < points_prev.size(); i++) { Vector2 tuv = mtx.xform(uv_create_poly_prev[i]); - real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); + real_t dist = tuv.distance_to(mb->get_position()); if (dist < 8 && dist < closest_dist) { closest = i; closest_dist = dist; @@ -626,7 +626,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { point_drag_index = -1; for (int i = 0; i < points_prev.size(); i++) { Vector2 tuv = mtx.xform(points_prev[i]); - if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < 8) { + if (tuv.distance_to(mb->get_position()) < 8) { uv_drag_from = tuv; point_drag_index = i; } @@ -643,7 +643,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { for (int i = 0; i < points_prev.size(); i++) { Vector2 tuv = mtx.xform(points_prev[i]); - real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); + real_t dist = tuv.distance_to(mb->get_position()); if (dist < 8 && dist < closest_dist) { closest = i; closest_dist = dist; @@ -695,7 +695,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { polys.write[j] = mtx.xform(points_prev[idx]); } - if (Geometry2D::is_point_in_polygon(Vector2(mb->get_position().x, mb->get_position().y), polys)) { + if (Geometry2D::is_point_in_polygon(mb->get_position(), polys)) { erase_index = i; break; } @@ -791,7 +791,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { switch (uv_move_current) { case UV_MODE_CREATE: { if (uv_create) { - uv_create_to = mtx.affine_inverse().xform(snap_point(Vector2(mm->get_position().x, mm->get_position().y))); + uv_create_to = mtx.affine_inverse().xform(snap_point(mm->get_position())); } } break; case UV_MODE_EDIT_POINT: { @@ -870,7 +870,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } break; case UV_MODE_PAINT_WEIGHT: case UV_MODE_CLEAR_WEIGHT: { - bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y); + bone_paint_pos = mm->get_position(); } break; default: { } @@ -905,10 +905,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_edit_draw->update(); CanvasItemEditor::get_singleton()->update_viewport(); } else if (polygon_create.size()) { - uv_create_to = mtx.affine_inverse().xform(Vector2(mm->get_position().x, mm->get_position().y)); + uv_create_to = mtx.affine_inverse().xform(mm->get_position()); uv_edit_draw->update(); } else if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) { - bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y); + bone_paint_pos = mm->get_position(); uv_edit_draw->update(); } } diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 0f889ce33d..eb5e527640 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -182,7 +182,7 @@ void Sprite2DEditor::_update_mesh_data() { if (node->is_region_enabled()) { rect = node->get_region_rect(); } else { - rect.size = Size2(image->get_width(), image->get_height()); + rect.size = image->get_size(); } Ref<BitMap> bm; @@ -209,7 +209,7 @@ void Sprite2DEditor::_update_mesh_data() { computed_uv.clear(); computed_indices.clear(); - Size2 img_size = Vector2(image->get_width(), image->get_height()); + Size2 img_size = image->get_size(); for (int i = 0; i < lines.size(); i++) { lines.write[i] = expand(lines[i], rect, epsilon); } diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index a0d841ccca..cfb2d63bc7 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -321,12 +321,12 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { prev_margin = margins[3]; } if (edited_margin >= 0) { - drag_from = Vector2(mb->get_position().x, mb->get_position().y); + drag_from = mb->get_position(); drag = true; } } if (edited_margin < 0 && snap_mode == SNAP_AUTOSLICE) { - Vector2 point = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); + Vector2 point = mtx.affine_inverse().xform(mb->get_position()); for (const Rect2 &E : autoslice_cache) { if (E.has_point(point)) { rect = E; @@ -372,7 +372,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } } } else if (edited_margin < 0) { - drag_from = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); + drag_from = mtx.affine_inverse().xform(mb->get_position()); if (snap_mode == SNAP_PIXEL) { drag_from = drag_from.snapped(Vector2(1, 1)); } else if (snap_mode == SNAP_GRID) { @@ -393,7 +393,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { for (int i = 0; i < 8; i++) { Vector2 tuv = endpoints[i]; - if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < handle_radius) { + if (tuv.distance_to(mb->get_position()) < handle_radius) { drag_index = i; } } diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index d75013cfcf..2a8a3216ed 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -94,12 +94,14 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla } // Copy the texture. - Rect2i src_rect = atlas_source->get_tile_texture_region(tile_id); - Rect2 dst_rect_wide = Rect2i(new_tile_rect_in_altas.position * new_texture_region_size, new_tile_rect_in_altas.size * new_texture_region_size); - if (dst_rect_wide.get_end().x > output_image->get_width() || dst_rect_wide.get_end().y > output_image->get_height()) { - output_image->crop(MAX(dst_rect_wide.get_end().x, output_image->get_width()), MAX(dst_rect_wide.get_end().y, output_image->get_height())); + for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(tile_id); frame++) { + Rect2i src_rect = atlas_source->get_tile_texture_region(tile_id, frame); + Rect2 dst_rect_wide = Rect2i(new_tile_rect_in_altas.position * new_texture_region_size, new_tile_rect_in_altas.size * new_texture_region_size); + if (dst_rect_wide.get_end().x > output_image->get_width() || dst_rect_wide.get_end().y > output_image->get_height()) { + output_image->crop(MAX(dst_rect_wide.get_end().x, output_image->get_width()), MAX(dst_rect_wide.get_end().y, output_image->get_height())); + } + output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, dst_rect_wide.get_center() - src_rect.size / 2); } - output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, dst_rect_wide.get_center() - src_rect.size / 2); } // Compute the atlas offset. diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 8d76f5f1b4..e98bd74b62 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -256,11 +256,15 @@ void TileAtlasView::_draw_base_tiles() { for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i); - // Update the y to max value. - Vector2i offset_pos = (margins + (atlas_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0)); + for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) { + // Update the y to max value. + int animation_columns = tile_set_atlas_source->get_tile_animation_columns(atlas_coords); + Vector2i frame_coords = atlas_coords + (tile_set_atlas_source->get_tile_size_in_atlas(atlas_coords) + tile_set_atlas_source->get_tile_animation_separation(atlas_coords)) * ((animation_columns > 0) ? Vector2i(frame % animation_columns, frame / animation_columns) : Vector2i(frame, 0)); + Vector2i offset_pos = (margins + (frame_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0)); - // Draw the tile. - TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0); + // Draw the tile. + TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame); + } } } } @@ -326,13 +330,18 @@ void TileAtlasView::_draw_base_tiles_shape_grid() { for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i tile_id = tile_set_atlas_source->get_tile_id(i); Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_effective_texture_offset(tile_id, 0); - Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id); - // Draw only if the tile shape fits in the texture region - Transform2D tile_xform; - tile_xform.set_origin(texture_region.get_center() + in_tile_base_offset); - tile_xform.set_scale(tile_shape_size); - tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, grid_color); + for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) { + Color color = grid_color; + if (frame > 0) { + color.a *= 0.3; + } + Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id); + Transform2D tile_xform; + tile_xform.set_origin(texture_region.get_center() + in_tile_base_offset); + tile_xform.set_scale(tile_shape_size); + tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, color); + } } } @@ -360,7 +369,7 @@ void TileAtlasView::_draw_alternatives() { Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i); current_pos.x = 0; int y_increment = 0; - Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(atlas_coords); + Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(atlas_coords).size; int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(atlas_coords); for (int j = 1; j < alternatives_count; j++) { int alternative_id = tile_set_atlas_source->get_alternative_tile_id(atlas_coords, j); @@ -370,18 +379,18 @@ void TileAtlasView::_draw_alternatives() { // Update the y to max value. Vector2i offset_pos = current_pos; if (transposed) { - offset_pos = (current_pos + Vector2(texture_region.size.y, texture_region.size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id)); - y_increment = MAX(y_increment, texture_region.size.x); + offset_pos = (current_pos + Vector2(texture_region_size.y, texture_region_size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id)); + y_increment = MAX(y_increment, texture_region_size.x); } else { - offset_pos = (current_pos + texture_region.size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id)); - y_increment = MAX(y_increment, texture_region.size.y); + offset_pos = (current_pos + texture_region_size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id)); + y_increment = MAX(y_increment, texture_region_size.y); } // Draw the tile. TileMap::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id); // Increment the x position. - current_pos.x += transposed ? texture_region.size.y : texture_region.size.x; + current_pos.x += transposed ? texture_region_size.y : texture_region_size.x; } if (alternatives_count > 1) { current_pos.y += y_increment; diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 9fdf5044d9..8b5b576369 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -790,7 +790,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over // Get the tile modulation. Color modulate = tile_data->get_modulate(); Color self_modulate = tile_map->get_self_modulate(); - modulate = Color(modulate.r * self_modulate.r, modulate.g * self_modulate.g, modulate.b * self_modulate.b, modulate.a * self_modulate.a); + modulate *= self_modulate; // Draw the tile. p_overlay->draw_texture_rect_region(atlas_source->get_texture(), dest_rect, source_rect, modulate * Color(1.0, 1.0, 1.0, 0.5), transpose, tile_set->is_uv_clipping()); @@ -1456,13 +1456,25 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); for (Set<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) { if (E->get().source_id == source_id && E->get().alternative_tile == 0) { - tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get().get_atlas_coords()), selection_color, false); + for (int frame = 0; frame < atlas->get_tile_animation_frames_count(E->get().get_atlas_coords()); frame++) { + Color color = selection_color; + if (frame > 0) { + color.a *= 0.3; + } + tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get().get_atlas_coords(), frame), color, false); + } } } // Draw the hovered tile. if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0 && !tile_set_dragging_selection) { - tile_atlas_control->draw_rect(atlas->get_tile_texture_region(hovered_tile.get_atlas_coords()), Color(1.0, 1.0, 1.0), false); + for (int frame = 0; frame < atlas->get_tile_animation_frames_count(hovered_tile.get_atlas_coords()); frame++) { + Color color = Color(1.0, 1.0, 1.0); + if (frame > 0) { + color.a *= 0.3; + } + tile_atlas_control->draw_rect(atlas->get_tile_texture_region(hovered_tile.get_atlas_coords(), frame), color, false); + } } // Draw the selection rect. diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 9370708a3e..54185d1d2a 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -135,45 +135,81 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na const Vector2i &coords = tiles.front()->get().tile; const int &alternative = tiles.front()->get().alternative; - if (alternative == 0 && p_name == "atlas_coords") { - Vector2i as_vector2i = Vector2i(p_value); - ERR_FAIL_COND_V(!tile_set_atlas_source->can_move_tile_in_atlas(coords, as_vector2i), false); - - if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) { - tiles_set_atlas_source_editor->selection.clear(); - tiles_set_atlas_source_editor->selection.insert({ as_vector2i, 0 }); - tiles_set_atlas_source_editor->_update_tile_id_label(); - } - - tile_set_atlas_source->move_tile_in_atlas(coords, as_vector2i); - tiles.clear(); - tiles.insert({ as_vector2i, 0 }); - emit_signal(SNAME("changed"), "atlas_coords"); - return true; - } else if (alternative == 0 && p_name == "size_in_atlas") { - Vector2i as_vector2i = Vector2i(p_value); - ERR_FAIL_COND_V(!tile_set_atlas_source->can_move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i), false); + if (alternative == 0) { + Vector<String> components = String(p_name).split("/", true, 2); + if (p_name == "atlas_coords") { + Vector2i as_vector2i = Vector2i(p_value); + bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(as_vector2i, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords); + ERR_FAIL_COND_V(!has_room_for_tile, false); + + if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) { + tiles_set_atlas_source_editor->selection.clear(); + tiles_set_atlas_source_editor->selection.insert({ as_vector2i, 0 }); + tiles_set_atlas_source_editor->_update_tile_id_label(); + } - tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i); - emit_signal(SNAME("changed"), "size_in_atlas"); - return true; - } else if (alternative > 0 && p_name == "alternative_id") { - int as_int = int(p_value); - ERR_FAIL_COND_V(as_int < 0, false); - ERR_FAIL_COND_V_MSG(tile_set_atlas_source->has_alternative_tile(coords, as_int), false, vformat("Cannot change alternative tile ID. Another alternative exists with id %d for tile at coords %s.", as_int, coords)); - - if (tiles_set_atlas_source_editor->selection.front()->get().alternative == alternative) { - tiles_set_atlas_source_editor->selection.clear(); - tiles_set_atlas_source_editor->selection.insert({ coords, as_int }); + tile_set_atlas_source->move_tile_in_atlas(coords, as_vector2i); + tiles.clear(); + tiles.insert({ as_vector2i, 0 }); + emit_signal(SNAME("changed"), "atlas_coords"); + return true; + } else if (p_name == "size_in_atlas") { + Vector2i as_vector2i = Vector2i(p_value); + bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, as_vector2i, tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords); + ERR_FAIL_COND_V(!has_room_for_tile, false); + tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i); + emit_signal(SNAME("changed"), "size_in_atlas"); + return true; + } else if (p_name == "animation_columns") { + bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), p_value, tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords); + ERR_FAIL_COND_V(!has_room_for_tile, false); + tile_set_atlas_source->set_tile_animation_columns(coords, p_value); + emit_signal(SNAME("changed"), "animation_columns"); + return true; + } else if (p_name == "animation_separation") { + bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), p_value, tile_set_atlas_source->get_tile_animation_frames_count(coords), coords); + ERR_FAIL_COND_V(!has_room_for_tile, false); + tile_set_atlas_source->set_tile_animation_separation(coords, p_value); + emit_signal(SNAME("changed"), "animation_separation"); + return true; + } else if (p_name == "animation_speed") { + tile_set_atlas_source->set_tile_animation_speed(coords, p_value); + emit_signal(SNAME("changed"), "animation_speed"); + return true; + } else if (p_name == "animation_frames_count") { + bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), p_value, coords); + ERR_FAIL_COND_V(!has_room_for_tile, false); + tile_set_atlas_source->set_tile_animation_frames_count(coords, p_value); + notify_property_list_changed(); + emit_signal(SNAME("changed"), "animation_separation"); + return true; + } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) { + int frame = components[0].trim_prefix("animation_frame_").to_int(); + ERR_FAIL_INDEX_V(frame, tile_set_atlas_source->get_tile_animation_frames_count(coords), false); + if (components[1] == "duration") { + tile_set_atlas_source->set_tile_animation_frame_duration(coords, frame, p_value); + return true; + } } + } else if (alternative > 0) { + if (p_name == "alternative_id") { + int as_int = int(p_value); + ERR_FAIL_COND_V(as_int < 0, false); + ERR_FAIL_COND_V_MSG(tile_set_atlas_source->has_alternative_tile(coords, as_int), false, vformat("Cannot change alternative tile ID. Another alternative exists with id %d for tile at coords %s.", as_int, coords)); + + if (tiles_set_atlas_source_editor->selection.front()->get().alternative == alternative) { + tiles_set_atlas_source_editor->selection.clear(); + tiles_set_atlas_source_editor->selection.insert({ coords, as_int }); + } - int previous_alternative_tile = alternative; - tiles.clear(); - tiles.insert({ coords, as_int }); // tiles must be updated before. - tile_set_atlas_source->set_alternative_tile_id(coords, previous_alternative_tile, as_int); + int previous_alternative_tile = alternative; + tiles.clear(); + tiles.insert({ coords, as_int }); // tiles must be updated before. + tile_set_atlas_source->set_alternative_tile_id(coords, previous_alternative_tile, as_int); - emit_signal(SNAME("changed"), "alternative_id"); - return true; + emit_signal(SNAME("changed"), "alternative_id"); + return true; + } } } @@ -206,15 +242,41 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na const Vector2i &coords = tiles.front()->get().tile; const int &alternative = tiles.front()->get().alternative; - if (alternative == 0 && p_name == "atlas_coords") { - r_ret = coords; - return true; - } else if (alternative == 0 && p_name == "size_in_atlas") { - r_ret = tile_set_atlas_source->get_tile_size_in_atlas(coords); - return true; - } else if (alternative > 0 && p_name == "alternative_id") { - r_ret = alternative; - return true; + if (alternative == 0) { + Vector<String> components = String(p_name).split("/", true, 2); + if (p_name == "atlas_coords") { + r_ret = coords; + return true; + } else if (p_name == "size_in_atlas") { + r_ret = tile_set_atlas_source->get_tile_size_in_atlas(coords); + return true; + } else if (p_name == "animation_columns") { + r_ret = tile_set_atlas_source->get_tile_animation_columns(coords); + return true; + } else if (p_name == "animation_separation") { + r_ret = tile_set_atlas_source->get_tile_animation_separation(coords); + return true; + } else if (p_name == "animation_speed") { + r_ret = tile_set_atlas_source->get_tile_animation_speed(coords); + return true; + } else if (p_name == "animation_frames_count") { + r_ret = tile_set_atlas_source->get_tile_animation_frames_count(coords); + return true; + } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) { + int frame = components[0].trim_prefix("animation_frame_").to_int(); + if (components[1] == "duration") { + if (frame < 0 || frame >= tile_set_atlas_source->get_tile_animation_frames_count(coords)) { + return false; + } + r_ret = tile_set_atlas_source->get_tile_animation_frame_duration(coords, frame); + return true; + } + } + } else if (alternative > 0) { + if (p_name == "alternative_id") { + r_ret = alternative; + return true; + } } } @@ -246,6 +308,20 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro if (tiles.front()->get().alternative == 0) { p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, "")); + + // Animation. + p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP)); + p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, "")); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, "")); + p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, "")); + p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_")); + if (tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile) == 1) { + p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_frame_0/duration", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); + } else { + for (int i = 0; i < tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile); i++) { + p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, "")); + } + } } else { p_list->push_back(PropertyInfo(Variant::INT, "alternative_id", PROPERTY_HINT_NONE, "")); } @@ -846,7 +922,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven CursorShape cursor_shape = CURSOR_ARROW; bool can_grow[4]; for (int i = 0; i < 4; i++) { - can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]); + can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile); can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; } for (int i = 0; i < 4; i++) { @@ -869,7 +945,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); new_rect.size += Vector2i(1, 1); // Check if the new tile can fit in the new rect. - if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) { + if (tile_set_atlas_source->has_room_for_tile(new_rect.position, new_rect.size, tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) { // Move and resize the tile. tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size); drag_current_tile = new_rect.position; @@ -908,7 +984,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size(); Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset); coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); - if (drag_current_tile != coords && tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, coords)) { + if (drag_current_tile != coords && tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile), tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) { tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords); selection.clear(); selection.insert({ coords, 0 }); @@ -948,7 +1024,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1))); } - if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) { + if (tile_set_atlas_source->has_room_for_tile(new_rect.position, new_rect.size, tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) { tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size); selection.clear(); selection.insert({ new_rect.position, 0 }); @@ -1056,7 +1132,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven CursorShape cursor_shape = CURSOR_ARROW; bool can_grow[4]; for (int i = 0; i < 4; i++) { - can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]); + can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile); can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; } for (int i = 0; i < 4; i++) { @@ -1511,37 +1587,45 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { TileSelection selected = E->get(); if (selected.alternative == 0) { // Draw the rect. - Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); - tile_atlas_control->draw_rect(region, selection_color, false); + for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(selected.tile); frame++) { + Color color = selection_color; + if (frame > 0) { + color.a *= 0.3; + } + Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile, frame); + tile_atlas_control->draw_rect(region, color, false); + } } } if (selection.size() == 1) { // Draw the resize handles (only when it's possible to expand). TileSelection selected = selection.front()->get(); - Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); - Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); - Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); - Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); - Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; - Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; - bool can_grow[4]; - for (int i = 0; i < 4; i++) { - can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]); - can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; - } - for (int i = 0; i < 4; i++) { - Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i]; - if (can_grow[i] && can_grow[(i + 3) % 4]) { - tile_atlas_control->draw_texture_rect(resize_handle, Rect2(pos, zoomed_size), false); - } else { - tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2(pos, zoomed_size), false); + if (selected.alternative == 0) { + Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); + Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); + Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); + Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); + Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; + Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; + bool can_grow[4]; + for (int i = 0; i < 4; i++) { + can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile); + can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; } - Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4]; - if (can_grow[i]) { - tile_atlas_control->draw_texture_rect(resize_handle, Rect2((pos + next_pos) / 2.0, zoomed_size), false); - } else { - tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2((pos + next_pos) / 2.0, zoomed_size), false); + for (int i = 0; i < 4; i++) { + Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i]; + if (can_grow[i] && can_grow[(i + 3) % 4]) { + tile_atlas_control->draw_texture_rect(resize_handle, Rect2(pos, zoomed_size), false); + } else { + tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2(pos, zoomed_size), false); + } + Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4]; + if (can_grow[i]) { + tile_atlas_control->draw_texture_rect(resize_handle, Rect2((pos + next_pos) / 2.0, zoomed_size), false); + } else { + tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2((pos + next_pos) / 2.0, zoomed_size), false); + } } } } @@ -1550,7 +1634,9 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { if (drag_type == DRAG_TYPE_REMOVE_TILES) { // Draw the tiles to be removed. for (Set<Vector2i>::Element *E = drag_modified_tiles.front(); E; E = E->next()) { - tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(E->get()), Color(0.0, 0.0, 0.0), false); + for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(E->get()); frame++) { + tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(E->get(), frame), Color(0.0, 0.0, 0.0), false); + } } } else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) { // Draw tiles to be removed. @@ -1617,7 +1703,13 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Vector2i hovered_tile = tile_set_atlas_source->get_tile_at_coords(hovered_base_tile_coords); if (hovered_tile != TileSetSource::INVALID_ATLAS_COORDS) { // Draw existing hovered tile. - tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile), Color(1.0, 1.0, 1.0), false); + for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(hovered_tile); frame++) { + Color color = Color(1.0, 1.0, 1.0); + if (frame > 0) { + color.a *= 0.3; + } + tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile, frame), color, false); + } } else { // Draw empty tile, only in add/remove tiles mode. if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) { diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 79b869b511..f51f4625a9 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -146,7 +146,7 @@ void TilesEditor::synchronize_atlas_view(Object *p_current) { ERR_FAIL_COND(!tile_atlas_view); if (tile_atlas_view->is_visible_in_tree()) { - tile_atlas_view->set_transform(atlas_view_zoom, Vector2(atlas_view_scroll.x, atlas_view_scroll.y)); + tile_atlas_view->set_transform(atlas_view_zoom, atlas_view_scroll); } } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index aaa085675c..27f30479cf 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1945,7 +1945,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p box_size.x -= 28 * EDSCALE; box_size.y -= text_box->get_offset(SIDE_TOP); box_size.y -= 28 * EDSCALE; - text_box->set_custom_minimum_size(Size2(box_size.x, box_size.y)); + text_box->set_custom_minimum_size(box_size); text_box->set_size(Size2(1, 1)); } } diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index d54bf73028..3de87d9df7 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -522,7 +522,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) { if (p_node == selected) { selected = nullptr; - emit_signal("node_selected"); + emit_signal(SNAME("node_selected")); } } @@ -630,7 +630,7 @@ void SceneTreeEditor::_selected_changed() { selected = get_node(np); blocked++; - emit_signal("node_selected"); + emit_signal(SNAME("node_selected")); blocked--; } @@ -757,7 +757,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) { } if (p_emit_selected) { - emit_signal("node_selected"); + emit_signal(SNAME("node_selected")); } } diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp index 7e6f154fab..6bbefb3bb2 100644 --- a/editor/shader_create_dialog.cpp +++ b/editor/shader_create_dialog.cpp @@ -190,7 +190,7 @@ void ShaderCreateDialog::_create_new() { } } - emit_signal("shader_created", shader); + emit_signal(SNAME("shader_created"), shader); hide(); } @@ -203,7 +203,7 @@ void ShaderCreateDialog::_load_exist() { return; } - emit_signal("shader_created", p_shader); + emit_signal(SNAME("shader_created"), p_shader); hide(); } @@ -404,18 +404,18 @@ String ShaderCreateDialog::_validate_path(const String &p_path) { void ShaderCreateDialog::_msg_script_valid(bool valid, const String &p_msg) { error_label->set_text("- " + p_msg); if (valid) { - error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); + error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("success_color"), SNAME("Editor"))); } else { - error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor")); + error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("error_color"), SNAME("Editor"))); } } void ShaderCreateDialog::_msg_path_valid(bool valid, const String &p_msg) { path_error_label->set_text("- " + p_msg); if (valid) { - path_error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); + path_error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("success_color"), SNAME("Editor"))); } else { - path_error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor")); + path_error_label->add_theme_color_override("font_color", gc->get_theme_color(SNAME("error_color"), SNAME("Editor"))); } } diff --git a/platform/uwp/SCsub b/platform/uwp/SCsub index 71c402358f..8726d32d61 100644 --- a/platform/uwp/SCsub +++ b/platform/uwp/SCsub @@ -7,7 +7,7 @@ files = [ "#platform/windows/windows_terminal_logger.cpp", "joypad_uwp.cpp", "context_egl_uwp.cpp", - "app.cpp", + "app_uwp.cpp", "os_uwp.cpp", ] diff --git a/platform/uwp/app.cpp b/platform/uwp/app_uwp.cpp index 1da17ffc5d..50e33e6c49 100644 --- a/platform/uwp/app.cpp +++ b/platform/uwp/app_uwp.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* app.cpp */ +/* app_uwp.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -32,7 +32,7 @@ // This file demonstrates how to initialize EGL in a Windows Store app, using ICoreWindow. // -#include "app.h" +#include "app_uwp.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" diff --git a/platform/uwp/app.h b/platform/uwp/app_uwp.h index 0b02527dae..8d4a0b90c3 100644 --- a/platform/uwp/app.h +++ b/platform/uwp/app_uwp.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* app.h */ +/* app_uwp.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#pragma once +#ifndef APP_UWP_H +#define APP_UWP_H #include <string> @@ -111,3 +112,4 @@ namespace GodotUWP } /* clang-format on */ +#endif // APP_UWP_H diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index b836497627..cf2632f380 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -155,7 +155,7 @@ void CPUParticles2D::_update_mesh_texture() { Vector<Vector2> vertices; vertices.push_back(-tex_size * 0.5); vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, 0)); - vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, tex_size.y)); + vertices.push_back(-tex_size * 0.5 + tex_size); vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y)); Vector<Vector2> uvs; AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 799ed47862..c3dc9ab92b 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -58,7 +58,8 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_t PhysicsServer2D::MotionResult result; if (move_and_collide(p_motion, result, p_margin, p_test_only)) { - if (motion_cache.is_null()) { + // Create a new instance when the cached reference is invalid or still in use in script. + if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { motion_cache.instantiate(); motion_cache->owner = this; } @@ -1369,7 +1370,8 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) { slide_colliders.resize(p_bounce + 1); } - if (slide_colliders[p_bounce].is_null()) { + // Create a new instance when the cached reference is invalid or still in use in script. + if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) { slide_colliders.write[p_bounce].instantiate(); slide_colliders.write[p_bounce]->owner = this; } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index a139a92ab4..03db9c0d32 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -891,7 +891,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List modulate.a *= 0.3; } } - draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, modulate); + draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate); // --- Occluders --- for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) { @@ -1008,15 +1008,19 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { } } -void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation) { +void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation) { ERR_FAIL_COND(!p_tile_set.is_valid()); ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id)); ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords)); ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile)); - TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id); TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); if (atlas_source) { + // Check for the frame. + if (p_frame >= 0) { + ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords)); + } + // Get the texture. Ref<Texture2D> tex = atlas_source->get_texture(); if (!tex.is_valid()) { @@ -1032,13 +1036,15 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe // Get tile data. TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile)); - // Compute the offset - Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords); + // Get the tile modulation. + Color modulate = tile_data->get_modulate() * p_modulation; + + // Compute the offset. Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(p_atlas_coords, p_alternative_tile); - // Compute the destination rectangle in the CanvasItem. + // Get destination rect. Rect2 dest_rect; - dest_rect.size = source_rect.size; + dest_rect.size = atlas_source->get_tile_texture_region(p_atlas_coords).size; dest_rect.size.x += FP_ADJUST; dest_rect.size.y += FP_ADJUST; @@ -1057,12 +1063,28 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe dest_rect.size.y = -dest_rect.size.y; } - // Get the tile modulation. - Color modulate = tile_data->get_modulate(); - modulate = Color(modulate.r * p_modulation.r, modulate.g * p_modulation.g, modulate.b * p_modulation.b, modulate.a * p_modulation.a); - // Draw the tile. - tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping()); + if (p_frame >= 0) { + Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, p_frame); + tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping()); + } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) { + Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, 0); + tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping()); + } else { + real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords); + real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed; + real_t time = 0.0; + for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) { + real_t frame_duration = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame) / speed; + RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, 0.0); + + Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, frame); + tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping()); + + time += frame_duration; + } + RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0); + } } } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 3ac50fc7cc..ca38baa550 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -305,7 +305,7 @@ public: void set_quadrant_size(int p_size); int get_quadrant_size() const; - static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0)); + static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0)); // Layers management. int get_layers_count() const; diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index 70361f4787..c34c150145 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -161,7 +161,7 @@ void BoneAttachment3D::_check_bind() { bone_idx = sk->find_bone(bone_name); } if (bone_idx != -1) { - sk->call_deferred("connect", "bone_pose_changed", callable_mp(this, &BoneAttachment3D::on_bone_pose_update)); + sk->call_deferred(SNAME("connect"), "bone_pose_changed", callable_mp(this, &BoneAttachment3D::on_bone_pose_update)); bound = true; call_deferred(SNAME("on_bone_pose_update"), bone_idx); } diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 7bd0a89eb3..48da186860 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -98,7 +98,8 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, int p_max_collisions) { PhysicsServer3D::MotionResult result; if (move_and_collide(p_motion, result, p_margin, p_test_only, p_max_collisions)) { - if (motion_cache.is_null()) { + // Create a new instance when the cached reference is invalid or still in use in script. + if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { motion_cache.instantiate(); motion_cache->owner = this; } @@ -1590,7 +1591,8 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) { slide_colliders.resize(p_bounce + 1); } - if (slide_colliders[p_bounce].is_null()) { + // Create a new instance when the cached reference is invalid or still in use in script. + if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->reference_get_count() > 1) { slide_colliders.write[p_bounce].instantiate(); slide_colliders.write[p_bounce]->owner = this; } diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 0f5de621ea..b7a79a2645 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -520,6 +520,7 @@ void Skeleton3D::set_bone_parent(int p_bone, int p_parent) { const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone, bone_size); ERR_FAIL_COND(p_parent != -1 && (p_parent < 0)); + ERR_FAIL_COND(p_bone == p_parent); bones.write[p_bone].parent = p_parent; process_order_dirty = true; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 4dfd6902e6..5d1106bb41 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -296,7 +296,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { mpos.x = get_size().x - mpos.x; } - Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y)); + Point2i pos = get_line_column_at_pos(mpos); int line = pos.y; int col = pos.x; @@ -321,7 +321,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { mpos.x = get_size().x - mpos.x; } - Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y)); + Point2i pos = get_line_column_at_pos(mpos); int line = pos.y; int col = pos.x; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index efb6b7d200..046715e17e 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -996,7 +996,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mev = p_event; if (mev.is_valid()) { Viewport *r = get_tree()->get_root(); - if (!r->get_visible_rect().has_point(Point2(mev->get_global_position().x, mev->get_global_position().y))) { + if (!r->get_visible_rect().has_point(mev->get_global_position())) { return; } diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index b9b02b1427..bca3b2059d 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -697,7 +697,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } else if (!just_disconnected) { String from = connecting_from; int from_slot = connecting_index; - Vector2 ofs = Vector2(mb->get_position().x, mb->get_position().y); + Vector2 ofs = mb->get_position(); if (!connecting_out) { emit_signal(SNAME("connection_from_empty"), from, from_slot, ofs); @@ -2103,7 +2103,7 @@ void GraphEdit::arrange_nodes() { largest_node_size = 0.0f; } - emit_signal("begin_node_move"); + emit_signal(SNAME("begin_node_move")); for (const Set<StringName>::Element *E = selected_nodes.front(); E; E = E->next()) { GraphNode *gn = Object::cast_to<GraphNode>(node_names[E->get()]); gn->set_drag(true); @@ -2116,7 +2116,7 @@ void GraphEdit::arrange_nodes() { gn->set_position_offset(pos); gn->set_drag(false); } - emit_signal("end_node_move"); + emit_signal(SNAME("end_node_move")); arranging_graph = false; } diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 08c8c60d7a..cbdf2a498a 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -871,7 +871,7 @@ void GraphNode::gui_input(const Ref<InputEvent> &p_ev) { ERR_FAIL_COND_MSG(get_parent_control() == nullptr, "GraphNode must be the child of a GraphEdit node."); if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { - Vector2 mpos = Vector2(mb->get_position().x, mb->get_position().y); + Vector2 mpos = mb->get_position(); if (close_rect.size != Size2() && close_rect.has_point(mpos)) { //send focus to parent get_parent_control()->grab_focus(); diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index e9414598a2..be05fd5a60 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -194,7 +194,7 @@ Popup::~Popup() { } Size2 PopupPanel::_get_contents_minimum_size() const { - Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name()); + Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name()); Size2 ms; @@ -217,7 +217,7 @@ Size2 PopupPanel::_get_contents_minimum_size() const { } void PopupPanel::_update_child_rects() { - Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name()); + Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name()); Vector2 cpos(p->get_offset()); Vector2 csize(get_size() - p->get_minimum_size()); @@ -244,9 +244,9 @@ void PopupPanel::_update_child_rects() { void PopupPanel::_notification(int p_what) { if (p_what == NOTIFICATION_THEME_CHANGED) { - panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name())); + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name())); } else if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) { - panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name())); + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name())); _update_child_rects(); } else if (p_what == NOTIFICATION_WM_SIZE_CHANGED) { _update_child_rects(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index eb88570663..3eaae5181d 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -333,7 +333,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> } else { frame->lines.write[i].offset.y = 0; } - frame->lines.write[i].offset += Vector2(offset.x, offset.y); + frame->lines.write[i].offset += offset; float h = frame->lines[i].text_buf->get_size().y; if (frame->min_size_over.y > 0) { @@ -578,7 +578,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> } else { frame->lines.write[i].offset.y = 0; } - frame->lines.write[i].offset += Vector2(offset.x, offset.y); + frame->lines.write[i].offset += offset; float h = frame->lines[i].text_buf->get_size().y; if (frame->min_size_over.y > 0) { diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 4edf373fbf..4a3a6837d5 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -560,7 +560,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) { if (mm.is_valid()) { if (drag_node_touching && !drag_node_touching_deaccel) { - Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y); + Vector2 motion = mm->get_relative(); drag_node_accum -= motion; Vector2 diff = drag_node_from + drag_node_accum; diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 0c051f61e2..0c0ec39c7f 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -167,7 +167,7 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { if (mm.is_valid()) { if (drag_touching && !drag_touching_deaccel) { - Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y); + Vector2 motion = mm->get_relative(); drag_accum -= motion; if (beyond_deadzone || (scroll_h && Math::abs(drag_accum.x) > deadzone) || (scroll_v && Math::abs(drag_accum.y) > deadzone)) { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 06dfc31621..09899413f2 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1444,7 +1444,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { _reset_caret_blink_timer(); - Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y)); + Point2i pos = get_line_column_at_pos(mpos); int row = pos.y; int col = pos.x; @@ -1547,7 +1547,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) { _reset_caret_blink_timer(); - Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y)); + Point2i pos = get_line_column_at_pos(mpos); int row = pos.y; int col = pos.x; @@ -5385,7 +5385,7 @@ void TextEdit::_update_selection_mode_pointer() { dragging_selection = true; Point2 mp = get_local_mouse_pos(); - Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y)); + Point2i pos = get_line_column_at_pos(mp); int line = pos.y; int col = pos.x; @@ -5402,7 +5402,7 @@ void TextEdit::_update_selection_mode_word() { dragging_selection = true; Point2 mp = get_local_mouse_pos(); - Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y)); + Point2i pos = get_line_column_at_pos(mp); int line = pos.y; int col = pos.x; @@ -5450,7 +5450,7 @@ void TextEdit::_update_selection_mode_line() { dragging_selection = true; Point2 mp = get_local_mouse_pos(); - Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y)); + Point2i pos = get_line_column_at_pos(mp); int line = pos.y; int col = pos.x; @@ -5765,7 +5765,7 @@ void TextEdit::_update_minimap_hover() { return; } - const int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y)); + const int row = get_minimap_line_at_pos(mp); const bool new_hovering_minimap = row >= get_first_visible_line() && row <= get_last_full_visible_line(); if (new_hovering_minimap != hovering_minimap) { @@ -5786,7 +5786,7 @@ void TextEdit::_update_minimap_click() { minimap_clicked = true; dragging_minimap = true; - int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y)); + int row = get_minimap_line_at_pos(mp); if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) { minimap_scroll_ratio = v_scroll->get_as_ratio(); diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index de557494c3..49ed9dcb82 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -48,7 +48,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol img->convert(Image::FORMAT_LA8); ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); - create(Size2(img->get_width(), img->get_height())); + create(img->get_size()); const uint8_t *r = img->get_data().ptr(); uint8_t *w = bitmask.ptrw(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 7346b6efc7..492e0512e4 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -51,7 +51,7 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl } else { texture = Ref<ImageTexture>(memnew(ImageTexture)); Ref<Image> img = memnew(Image(p_src)); - const Size2 orig_size = Size2(img->get_width(), img->get_height()); + const Size2 orig_size = img->get_size(); img->convert(Image::FORMAT_RGBA8); img->resize(orig_size.x * scale, orig_size.y * scale); @@ -97,7 +97,7 @@ template <class T> static Ref<Texture2D> make_icon(T p_src) { Ref<ImageTexture> texture(memnew(ImageTexture)); Ref<Image> img = memnew(Image(p_src)); - const Size2 orig_size = Size2(img->get_width(), img->get_height()); + const Size2 orig_size = img->get_size(); img->convert(Image::FORMAT_RGBA8); img->resize(orig_size.x * scale, orig_size.y * scale); texture->create_from_image(img); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 918fc3fe9c..67cbd0e094 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -3119,7 +3119,7 @@ Vector2i TileSetAtlasSource::get_atlas_grid_size() const { } bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) { - Vector<String> components = String(p_name).split("/", true, 2); + Vector<String> components = String(p_name).split("/", true, 3); // Compute the vector2i if we have coordinates. Vector<String> coords_split = components[0].split(":"); @@ -3138,8 +3138,32 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) // Properties. if (components[1] == "size_in_atlas") { move_tile_in_atlas(coords, coords, p_value); + return true; } else if (components[1] == "next_alternative_id") { tiles[coords].next_alternative_id = p_value; + return true; + } else if (components[1] == "animation_columns") { + set_tile_animation_columns(coords, p_value); + return true; + } else if (components[1] == "animation_separation") { + set_tile_animation_separation(coords, p_value); + return true; + } else if (components[1] == "animation_speed") { + set_tile_animation_speed(coords, p_value); + return true; + } else if (components[1] == "animation_frames_count") { + set_tile_animation_frames_count(coords, p_value); + return true; + } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) { + int frame = components[1].trim_prefix("animation_frame_").to_int(); + if (components[2] == "duration") { + if (frame >= get_tile_animation_frames_count(coords)) { + set_tile_animation_frames_count(coords, frame + 1); + } + set_tile_animation_frame_duration(coords, frame, p_value); + return true; + } + return false; } else if (components[1].is_valid_int()) { int alternative_id = components[1].to_int(); if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) { @@ -3185,6 +3209,28 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const { } else if (components[1] == "next_alternative_id") { r_ret = tiles[coords].next_alternative_id; return true; + } else if (components[1] == "animation_columns") { + r_ret = get_tile_animation_columns(coords); + return true; + } else if (components[1] == "animation_separation") { + r_ret = get_tile_animation_separation(coords); + return true; + } else if (components[1] == "animation_speed") { + r_ret = get_tile_animation_speed(coords); + return true; + } else if (components[1] == "animation_frames_count") { + r_ret = get_tile_animation_frames_count(coords); + return true; + } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) { + int frame = components[1].trim_prefix("animation_frame_").to_int(); + if (frame < 0 || frame >= get_tile_animation_frames_count(coords)) { + return false; + } + if (components[2] == "duration") { + r_ret = get_tile_animation_frame_duration(coords, frame); + return true; + } + return false; } else if (components[1].is_valid_int()) { int alternative_id = components[1].to_int(); if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) { @@ -3226,6 +3272,40 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const { } tile_property_list.push_back(property_info); + // animation_columns. + property_info = PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR); + if (E_tile->get().animation_columns == 0) { + property_info.usage ^= PROPERTY_USAGE_STORAGE; + } + tile_property_list.push_back(property_info); + + // animation_separation. + property_info = PropertyInfo(Variant::INT, "animation_separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR); + if (E_tile->get().animation_separation == Vector2i()) { + property_info.usage ^= PROPERTY_USAGE_STORAGE; + } + tile_property_list.push_back(property_info); + + // animation_speed. + property_info = PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR); + if (E_tile->get().animation_speed == 1.0) { + property_info.usage ^= PROPERTY_USAGE_STORAGE; + } + tile_property_list.push_back(property_info); + + // animation_frames_count. + tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NETWORK)); + + // animation_frame_*. + bool store_durations = tiles[E_tile->key()].animation_frames_durations.size() >= 2; + for (int i = 0; i < (int)tiles[E_tile->key()].animation_frames_durations.size(); i++) { + property_info = PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR); + if (!store_durations) { + property_info.usage ^= PROPERTY_USAGE_STORAGE; + } + tile_property_list.push_back(property_info); + } + for (Map<int, TileData *>::Element *E_alternative = E_tile->get().alternatives.front(); E_alternative; E_alternative = E_alternative->next()) { // Add a dummy property to show the alternative exists. tile_property_list.push_back(PropertyInfo(Variant::INT, vformat("%d", E_alternative->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); @@ -3234,11 +3314,10 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const { List<PropertyInfo> alternative_property_list; E_alternative->get()->get_property_list(&alternative_property_list); for (PropertyInfo &alternative_property_info : alternative_property_list) { - bool valid; - Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name, &valid); + Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name); Variant value = E_alternative->get()->get(alternative_property_info.name); - if (valid && value == default_value) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; + if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) { + alternative_property_info.usage ^= PROPERTY_USAGE_STORAGE; } alternative_property_info.name = vformat("%s/%s", vformat("%d", E_alternative->key()), alternative_property_info.name); tile_property_list.push_back(alternative_property_info); @@ -3257,33 +3336,27 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector // Create a tile if it does not exists. ERR_FAIL_COND(p_atlas_coords.x < 0 || p_atlas_coords.y < 0); ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0); - for (int x = 0; x < p_size.x; x++) { - for (int y = 0; y < p_size.y; y++) { - Vector2i coords = p_atlas_coords + Vector2i(x, y); - ERR_FAIL_COND_MSG(tiles.has(coords), vformat("Cannot create tile at position %s with size %s. Already a tile present at %s.", p_atlas_coords, p_size, coords)); - } - } + + bool room_for_tile = has_room_for_tile(p_atlas_coords, p_size, 1, Vector2i(), 1); + ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile, tiles are already present in the space the tile would cover."); + + // Initialize the tile data. + TileAlternativesData tad; + tad.size_in_atlas = p_size; + tad.animation_frames_durations.push_back(1.0); + tad.alternatives[0] = memnew(TileData); + tad.alternatives[0]->set_tile_set(tile_set); + tad.alternatives[0]->set_allow_transform(false); + tad.alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed)); + tad.alternatives[0]->notify_property_list_changed(); + tad.alternatives_ids.append(0); // Create and resize the tile. - tiles.insert(p_atlas_coords, TileSetAtlasSource::TileAlternativesData()); + tiles.insert(p_atlas_coords, tad); tiles_ids.append(p_atlas_coords); tiles_ids.sort(); - tiles[p_atlas_coords].size_in_atlas = p_size; - tiles[p_atlas_coords].alternatives[0] = memnew(TileData); - tiles[p_atlas_coords].alternatives[0]->set_tile_set(tile_set); - tiles[p_atlas_coords].alternatives[0]->set_allow_transform(false); - tiles[p_atlas_coords].alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed)); - tiles[p_atlas_coords].alternatives[0]->notify_property_list_changed(); - tiles[p_atlas_coords].alternatives_ids.append(0); - - // Add all covered positions to the mapping cache - for (int x = 0; x < p_size.x; x++) { - for (int y = 0; y < p_size.y; y++) { - Vector2i coords = p_atlas_coords + Vector2i(x, y); - _coords_mapping_cache[coords] = p_atlas_coords; - } - } + _create_coords_mapping_cache(p_atlas_coords); emit_signal(SNAME("changed")); } @@ -3292,14 +3365,7 @@ void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) { ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); // Remove all covered positions from the mapping cache - Size2i size = tiles[p_atlas_coords].size_in_atlas; - - for (int x = 0; x < size.x; x++) { - for (int y = 0; y < size.y; y++) { - Vector2i coords = p_atlas_coords + Vector2i(x, y); - _coords_mapping_cache.erase(coords); - } - } + _clear_coords_mapping_cache(p_atlas_coords); // Free tile data. for (Map<int, TileData *>::Element *E_tile_data = tiles[p_atlas_coords].alternatives.front(); E_tile_data; E_tile_data = E_tile_data->next()) { @@ -3326,6 +3392,118 @@ Vector2i TileSetAtlasSource::get_tile_at_coords(Vector2i p_atlas_coords) const { return _coords_mapping_cache[p_atlas_coords]; } +void TileSetAtlasSource::set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns) { + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + ERR_FAIL_COND(p_frame_columns < 0); + + TileAlternativesData &tad = tiles[p_atlas_coords]; + bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, p_frame_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords); + ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover."); + + _clear_coords_mapping_cache(p_atlas_coords); + + tiles[p_atlas_coords].animation_columns = p_frame_columns; + + _create_coords_mapping_cache(p_atlas_coords); + + emit_signal(SNAME("changed")); +} + +int TileSetAtlasSource::get_tile_animation_columns(const Vector2i p_atlas_coords) const { + ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + return tiles[p_atlas_coords].animation_columns; +} + +void TileSetAtlasSource::set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation) { + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + ERR_FAIL_COND(p_separation.x < 0 || p_separation.y < 0); + + TileAlternativesData &tad = tiles[p_atlas_coords]; + bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, p_separation, tad.animation_frames_durations.size(), p_atlas_coords); + ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover."); + + _clear_coords_mapping_cache(p_atlas_coords); + + tiles[p_atlas_coords].animation_separation = p_separation; + + _create_coords_mapping_cache(p_atlas_coords); + + emit_signal(SNAME("changed")); +} + +Vector2i TileSetAtlasSource::get_tile_animation_separation(const Vector2i p_atlas_coords) const { + ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + return tiles[p_atlas_coords].animation_separation; +} + +void TileSetAtlasSource::set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed) { + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + ERR_FAIL_COND(p_speed <= 0); + + tiles[p_atlas_coords].animation_speed = p_speed; + + emit_signal(SNAME("changed")); +} + +real_t TileSetAtlasSource::get_tile_animation_speed(const Vector2i p_atlas_coords) const { + ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1.0, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + return tiles[p_atlas_coords].animation_speed; +} + +void TileSetAtlasSource::set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count) { + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + ERR_FAIL_COND(p_frames_count < 1); + + TileAlternativesData &tad = tiles[p_atlas_coords]; + bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, tad.animation_separation, p_frames_count, p_atlas_coords); + ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover."); + + _clear_coords_mapping_cache(p_atlas_coords); + + int old_size = tiles[p_atlas_coords].animation_frames_durations.size(); + tiles[p_atlas_coords].animation_frames_durations.resize(p_frames_count); + for (int i = old_size; i < p_frames_count; i++) { + tiles[p_atlas_coords].animation_frames_durations[i] = 1.0; + } + + _create_coords_mapping_cache(p_atlas_coords); + + notify_property_list_changed(); + + emit_signal(SNAME("changed")); +} + +int TileSetAtlasSource::get_tile_animation_frames_count(const Vector2i p_atlas_coords) const { + ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + return tiles[p_atlas_coords].animation_frames_durations.size(); +} + +void TileSetAtlasSource::set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration) { + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + ERR_FAIL_INDEX(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size()); + ERR_FAIL_COND(p_duration <= 0.0); + + tiles[p_atlas_coords].animation_frames_durations[p_frame_index] = p_duration; + + emit_signal(SNAME("changed")); +} + +real_t TileSetAtlasSource::get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const { + ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + ERR_FAIL_INDEX_V(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size(), 0.0); + return tiles[p_atlas_coords].animation_frames_durations[p_frame_index]; +} + +real_t TileSetAtlasSource::get_tile_animation_total_duration(const Vector2i p_atlas_coords) const { + ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + + real_t sum = 0.0; + for (int frame = 0; frame < (int)tiles[p_atlas_coords].animation_frames_durations.size(); frame++) { + sum += tiles[p_atlas_coords].animation_frames_durations[frame]; + } + return sum; +} + Vector2i TileSetAtlasSource::get_tile_size_in_atlas(Vector2i p_atlas_coords) const { ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(-1, -1), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); @@ -3341,16 +3519,34 @@ Vector2i TileSetAtlasSource::get_tile_id(int p_index) const { return tiles_ids[p_index]; } -Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords) const { +bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile) const { + for (int frame = 0; frame < p_frames_count; frame++) { + Vector2i frame_coords = p_atlas_coords + (p_size + p_animation_separation) * ((p_animation_columns > 0) ? Vector2i(frame % p_animation_columns, frame / p_animation_columns) : Vector2i(frame, 0)); + for (int x = 0; x < p_size.x; x++) { + for (int y = 0; y < p_size.y; y++) { + Vector2i coords = frame_coords + Vector2i(x, y); + if (_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] != p_ignored_tile) { + return false; + } + } + } + } + return true; +} + +Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const { ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); + ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i()); + + const TileAlternativesData &tad = tiles[p_atlas_coords]; - Vector2i size_in_atlas = tiles[p_atlas_coords].size_in_atlas; + Vector2i size_in_atlas = tad.size_in_atlas; Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1)); - Vector2 origin = margins + (p_atlas_coords * (texture_region_size + separation)); + Vector2i frame_coords = p_atlas_coords + (size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(p_frame % tad.animation_columns, p_frame / tad.animation_columns) : Vector2i(p_frame, 0)); + Vector2 origin = margins + (frame_coords * (texture_region_size + separation)); return Rect2(origin, region_size); - ; } Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const { @@ -3369,56 +3565,23 @@ Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_ return effective_texture_offset; } -bool TileSetAtlasSource::can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) const { - ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); - - Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords; - if (new_atlas_coords.x < 0 || new_atlas_coords.y < 0) { - return false; - } - - Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas; - ERR_FAIL_COND_V(size.x <= 0 || size.y <= 0, false); - - Size2i grid_size = get_atlas_grid_size(); - if (new_atlas_coords.x + size.x > grid_size.x || new_atlas_coords.y + size.y > grid_size.y) { - return false; - } - - Rect2i new_rect = Rect2i(new_atlas_coords, size); - // Check if the new tile can fit in the new rect. - for (int x = new_rect.position.x; x < new_rect.get_end().x; x++) { - for (int y = new_rect.position.y; y < new_rect.get_end().y; y++) { - Vector2i coords = get_tile_at_coords(Vector2i(x, y)); - if (coords != p_atlas_coords && coords != TileSetSource::INVALID_ATLAS_COORDS) { - return false; - } - } - } - - return true; -} - void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) { - bool can_move = can_move_tile_in_atlas(p_atlas_coords, p_new_atlas_coords, p_new_size); - ERR_FAIL_COND_MSG(!can_move, vformat("Cannot move tile at position %s with size %s. Tile already present.", p_new_atlas_coords, p_new_size)); + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); + + TileAlternativesData &tad = tiles[p_atlas_coords]; // Compute the actual new rect from arguments. Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords; - Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas; + Vector2i new_size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tad.size_in_atlas; - if (new_atlas_coords == p_atlas_coords && size == tiles[p_atlas_coords].size_in_atlas) { + if (new_atlas_coords == p_atlas_coords && new_size == tad.size_in_atlas) { return; } - // Remove all covered positions from the mapping cache. - Size2i old_size = tiles[p_atlas_coords].size_in_atlas; - for (int x = 0; x < old_size.x; x++) { - for (int y = 0; y < old_size.y; y++) { - Vector2i coords = p_atlas_coords + Vector2i(x, y); - _coords_mapping_cache.erase(coords); - } - } + bool room_for_tile = has_room_for_tile(new_atlas_coords, new_size, tad.animation_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords); + ERR_FAIL_COND_MSG(!room_for_tile, vformat("Cannot move tile at position %s with size %s. Tile already present.", new_atlas_coords, new_size)); + + _clear_coords_mapping_cache(p_atlas_coords); // Move the tile and update its size. if (new_atlas_coords != p_atlas_coords) { @@ -3429,15 +3592,9 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_ tiles_ids.append(new_atlas_coords); tiles_ids.sort(); } - tiles[new_atlas_coords].size_in_atlas = size; + tiles[new_atlas_coords].size_in_atlas = new_size; - // Add all covered positions to the mapping cache again. - for (int x = 0; x < size.x; x++) { - for (int y = 0; y < size.y; y++) { - Vector2i coords = new_atlas_coords + Vector2i(x, y); - _coords_mapping_cache[coords] = new_atlas_coords; - } - } + _create_coords_mapping_cache(new_atlas_coords); emit_signal(SNAME("changed")); } @@ -3566,12 +3723,25 @@ void TileSetAtlasSource::_bind_methods() { // Base tiles ClassDB::bind_method(D_METHOD("create_tile", "atlas_coords", "size"), &TileSetAtlasSource::create_tile, DEFVAL(Vector2i(1, 1))); ClassDB::bind_method(D_METHOD("remove_tile", "atlas_coords"), &TileSetAtlasSource::remove_tile); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative - ClassDB::bind_method(D_METHOD("can_move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::can_move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1))); ClassDB::bind_method(D_METHOD("move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1))); ClassDB::bind_method(D_METHOD("get_tile_size_in_atlas", "atlas_coords"), &TileSetAtlasSource::get_tile_size_in_atlas); + ClassDB::bind_method(D_METHOD("has_room_for_tile", "atlas_coords", "size", "animation_columns", "animation_separation", "frames_count", "ignored_tile"), &TileSetAtlasSource::has_room_for_tile, DEFVAL(INVALID_ATLAS_COORDS)); + ClassDB::bind_method(D_METHOD("get_tile_at_coords", "atlas_coords"), &TileSetAtlasSource::get_tile_at_coords); + ClassDB::bind_method(D_METHOD("set_tile_animation_columns", "atlas_coords", "frame_columns"), &TileSetAtlasSource::set_tile_animation_columns); + ClassDB::bind_method(D_METHOD("get_tile_animation_columns", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_columns); + ClassDB::bind_method(D_METHOD("set_tile_animation_separation", "atlas_coords", "separation"), &TileSetAtlasSource::set_tile_animation_separation); + ClassDB::bind_method(D_METHOD("get_tile_animation_separation", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_separation); + ClassDB::bind_method(D_METHOD("set_tile_animation_speed", "atlas_coords", "speed"), &TileSetAtlasSource::set_tile_animation_speed); + ClassDB::bind_method(D_METHOD("get_tile_animation_speed", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_speed); + ClassDB::bind_method(D_METHOD("set_tile_animation_frames_count", "atlas_coords", "frames_count"), &TileSetAtlasSource::set_tile_animation_frames_count); + ClassDB::bind_method(D_METHOD("get_tile_animation_frames_count", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_frames_count); + ClassDB::bind_method(D_METHOD("set_tile_animation_frame_duration", "atlas_coords", "frame_index", "duration"), &TileSetAtlasSource::set_tile_animation_frame_duration); + ClassDB::bind_method(D_METHOD("get_tile_animation_frame_duration", "atlas_coords", "frame_index"), &TileSetAtlasSource::get_tile_animation_frame_duration); + ClassDB::bind_method(D_METHOD("get_tile_animation_total_duration", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_total_duration); + // Alternative tiles ClassDB::bind_method(D_METHOD("create_alternative_tile", "atlas_coords", "alternative_id_override"), &TileSetAtlasSource::create_alternative_tile, DEFVAL(INVALID_TILE_ALTERNATIVE)); ClassDB::bind_method(D_METHOD("remove_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::remove_alternative_tile); @@ -3584,7 +3754,7 @@ void TileSetAtlasSource::_bind_methods() { ClassDB::bind_method(D_METHOD("get_atlas_grid_size"), &TileSetAtlasSource::get_atlas_grid_size); ClassDB::bind_method(D_METHOD("has_tiles_outside_texture"), &TileSetAtlasSource::has_tiles_outside_texture); ClassDB::bind_method(D_METHOD("clear_tiles_outside_texture"), &TileSetAtlasSource::clear_tiles_outside_texture); - ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords"), &TileSetAtlasSource::get_tile_texture_region); + ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0)); } TileSetAtlasSource::~TileSetAtlasSource() { @@ -3618,6 +3788,45 @@ void TileSetAtlasSource::_compute_next_alternative_id(const Vector2i p_atlas_coo }; } +void TileSetAtlasSource::_clear_coords_mapping_cache(Vector2i p_atlas_coords) { + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + TileAlternativesData &tad = tiles[p_atlas_coords]; + for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) { + Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0)); + for (int x = 0; x < tad.size_in_atlas.x; x++) { + for (int y = 0; y < tad.size_in_atlas.y; y++) { + Vector2i coords = frame_coords + Vector2i(x, y); + if (!_coords_mapping_cache.has(coords)) { + WARN_PRINT(vformat("TileSetAtlasSource has no cached tile at position %s, the position cache might be corrupted.", coords)); + } else { + if (_coords_mapping_cache[coords] != p_atlas_coords) { + WARN_PRINT(vformat("The position cache at position %s is pointing to a wrong tile, the position cache might be corrupted.", coords)); + } + _coords_mapping_cache.erase(coords); + } + } + } + } +} + +void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) { + ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords))); + + TileAlternativesData &tad = tiles[p_atlas_coords]; + for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) { + Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0)); + for (int x = 0; x < tad.size_in_atlas.x; x++) { + for (int y = 0; y < tad.size_in_atlas.y; y++) { + Vector2i coords = frame_coords + Vector2i(x, y); + if (_coords_mapping_cache.has(coords)) { + WARN_PRINT(vformat("The cache already has a tile for position %s, the position cache might be corrupted.", coords)); + } + _coords_mapping_cache[coords] = p_atlas_coords; + } + } + } +} + /////////////////////////////// TileSetScenesCollectionSource ////////////////////////////////////// void TileSetScenesCollectionSource::_compute_next_alternative_id() { diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index ba7207241a..46cb1fb36d 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -447,16 +447,23 @@ public: class TileSetAtlasSource : public TileSetSource { GDCLASS(TileSetAtlasSource, TileSetSource); -public: +private: struct TileAlternativesData { Vector2i size_in_atlas = Vector2i(1, 1); Vector2i texture_offset; + + // Animation + int animation_columns = 0; + Vector2i animation_separation; + real_t animation_speed = 1.0; + LocalVector<real_t> animation_frames_durations; + + // Alternatives Map<int, TileData *> alternatives; Vector<int> alternatives_ids; int next_alternative_id = 1; }; -private: Ref<Texture2D> texture; Vector2i margins; Vector2i separation; @@ -471,6 +478,9 @@ private: void _compute_next_alternative_id(const Vector2i p_atlas_coords); + void _create_coords_mapping_cache(Vector2i p_atlas_coords); + void _clear_coords_mapping_cache(Vector2i p_atlas_coords); + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -513,18 +523,32 @@ public: Vector2i get_texture_region_size() const; // Base tiles. - void create_tile(const Vector2i p_atlas_coords, const Vector2i p_size = Vector2i(1, 1)); // Create a tile if it does not exists, or add alternative tile if it does. - void remove_tile(Vector2i p_atlas_coords); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative + void create_tile(const Vector2i p_atlas_coords, const Vector2i p_size = Vector2i(1, 1)); + void remove_tile(Vector2i p_atlas_coords); virtual bool has_tile(Vector2i p_atlas_coords) const override; - bool can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1)) const; void move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1)); Vector2i get_tile_size_in_atlas(Vector2i p_atlas_coords) const; virtual int get_tiles_count() const override; virtual Vector2i get_tile_id(int p_index) const override; + bool has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile = INVALID_ATLAS_COORDS) const; + Vector2i get_tile_at_coords(Vector2i p_atlas_coords) const; + // Animation. + void set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns); + int get_tile_animation_columns(const Vector2i p_atlas_coords) const; + void set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation); + Vector2i get_tile_animation_separation(const Vector2i p_atlas_coords) const; + void set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed); + real_t get_tile_animation_speed(const Vector2i p_atlas_coords) const; + void set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count); + int get_tile_animation_frames_count(const Vector2i p_atlas_coords) const; + void set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration); + real_t get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const; + real_t get_tile_animation_total_duration(const Vector2i p_atlas_coords) const; + // Alternative tiles. int create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override = -1); void remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile); @@ -542,7 +566,7 @@ public: Vector2i get_atlas_grid_size() const; bool has_tiles_outside_texture(); void clear_tiles_outside_texture(); - Rect2i get_tile_texture_region(Vector2i p_atlas_coords) const; + Rect2i get_tile_texture_region(Vector2i p_atlas_coords, int p_frame = 0) const; Vector2i get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const; ~TileSetAtlasSource(); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index efa3a457d3..456c736731 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -182,7 +182,7 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * if (ci->commands != nullptr) { ci->final_transform = xform; - ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a); + ci->final_modulate = modulate * ci->self_modulate; ci->global_rect_cache = global_rect; ci->global_rect_cache.position -= p_clip_rect.position; ci->light_masked = false; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index fa66ed85a9..8e31ec1d8b 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -3365,7 +3365,7 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Vector3 decal_extents = storage->decal_get_extents(decal); Transform3D scale_xform; - scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z)); + scale_xform.basis.scale(decal_extents); Transform3D to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse(); RendererStorageRD::store_transform(to_decal_xform, dd.xform); |