summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/extension/gdnative_interface.cpp10
-rw-r--r--core/extension/gdnative_interface.h4
-rw-r--r--core/math/aabb.cpp4
-rw-r--r--core/object/class_db.cpp9
-rw-r--r--core/object/class_db.h1
-rw-r--r--core/templates/pooled_list.h14
-rw-r--r--doc/classes/TileSetAtlasSource.xml111
-rw-r--r--editor/animation_bezier_editor.cpp4
-rw-r--r--editor/debugger/script_editor_debugger.cpp8
-rw-r--r--editor/editor_audio_buses.cpp2
-rw-r--r--editor/editor_command_palette.cpp6
-rw-r--r--editor/editor_file_dialog.cpp2
-rw-r--r--editor/editor_node.cpp8
-rw-r--r--editor/editor_properties.cpp4
-rw-r--r--editor/editor_resource_picker.cpp2
-rw-r--r--editor/import/dynamicfont_import_settings.cpp33
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp2
-rw-r--r--editor/import_dock.cpp18
-rw-r--r--editor/import_dock.h1
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp24
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp8
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp12
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp41
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp18
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp242
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--editor/scene_tree_editor.cpp6
-rw-r--r--editor/shader_create_dialog.cpp12
-rw-r--r--platform/uwp/SCsub2
-rw-r--r--platform/uwp/app_uwp.cpp (renamed from platform/uwp/app.cpp)4
-rw-r--r--platform/uwp/app_uwp.h (renamed from platform/uwp/app.h)6
-rw-r--r--scene/2d/cpu_particles_2d.cpp2
-rw-r--r--scene/2d/physics_body_2d.cpp6
-rw-r--r--scene/2d/tile_map.cpp46
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/3d/bone_attachment_3d.cpp2
-rw-r--r--scene/3d/physics_body_3d.cpp6
-rw-r--r--scene/3d/skeleton_3d.cpp1
-rw-r--r--scene/gui/code_edit.cpp4
-rw-r--r--scene/gui/color_picker.cpp2
-rw-r--r--scene/gui/graph_edit.cpp6
-rw-r--r--scene/gui/graph_node.cpp2
-rw-r--r--scene/gui/popup.cpp8
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--scene/gui/scroll_bar.cpp2
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/text_edit.cpp14
-rw-r--r--scene/resources/bit_map.cpp2
-rw-r--r--scene/resources/default_theme/default_theme.cpp4
-rw-r--r--scene/resources/tile_set.cpp391
-rw-r--r--scene/resources/tile_set.h36
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2
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);