Prevent tiles outside atlas texture
This commit is contained in:
parent
3be18d3d37
commit
b9151860f3
7 changed files with 151 additions and 124 deletions
|
@ -15,12 +15,6 @@
|
|||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="clear_tiles_outside_texture">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Clears all tiles that are defined outside the texture boundaries.
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_alternative_tile">
|
||||
<return type="int" />
|
||||
<argument index="0" name="atlas_coords" type="Vector2i" />
|
||||
|
@ -124,6 +118,16 @@
|
|||
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="get_tiles_to_be_removed_on_change">
|
||||
<return type="PackedVector2Array" />
|
||||
<argument index="0" name="texture" type="Texture2D" />
|
||||
<argument index="1" name="margins" type="Vector2i" />
|
||||
<argument index="2" name="separation" type="Vector2i" />
|
||||
<argument index="3" name="texture_region_size" type="Vector2i" />
|
||||
<description>
|
||||
Returns an array of tiles coordinates ID that will be automatically removed when modifying one or several of those properties: [code]texture[/code], [code]margins[/code], [code]separation[/code] or [code]texture_region_size[/code]. This can be used to undo changes that would have caused tiles data loss.
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_room_for_tile" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="atlas_coords" type="Vector2i" />
|
||||
|
@ -136,12 +140,6 @@
|
|||
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">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns if this atlas has tiles outside of its texture.
|
||||
</description>
|
||||
</method>
|
||||
<method name="move_tile_in_atlas">
|
||||
<return type="void" />
|
||||
<argument index="0" name="atlas_coords" type="Vector2i" />
|
||||
|
|
|
@ -97,15 +97,6 @@ Size2i TileAtlasView::_compute_base_tiles_control_size() {
|
|||
if (texture.is_valid()) {
|
||||
size = texture->get_size();
|
||||
}
|
||||
|
||||
// Extend the size to all existing tiles.
|
||||
Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
|
||||
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
|
||||
Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
|
||||
grid_size = grid_size.max(tile_id + Vector2i(1, 1));
|
||||
}
|
||||
size = size.max(grid_size * (tile_set_atlas_source->get_texture_region_size() + tile_set_atlas_source->get_separation()) + tile_set_atlas_source->get_margins());
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -213,43 +204,56 @@ void TileAtlasView::_draw_base_tiles() {
|
|||
Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
|
||||
if (texture.is_valid()) {
|
||||
Vector2i margins = tile_set_atlas_source->get_margins();
|
||||
Vector2i separation = tile_set_atlas_source->get_separation();
|
||||
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
|
||||
|
||||
// Draw the texture, square by square.
|
||||
Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
|
||||
|
||||
// Draw the texture where there is no tile.
|
||||
for (int x = 0; x < grid_size.x; x++) {
|
||||
for (int y = 0; y < grid_size.y; y++) {
|
||||
Vector2i coords = Vector2i(x, y);
|
||||
if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
|
||||
Rect2i rect = Rect2i(texture_region_size * coords + margins, texture_region_size);
|
||||
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
|
||||
Rect2i rect = Rect2i((texture_region_size + separation) * coords + margins, texture_region_size + separation);
|
||||
rect = rect.intersection(Rect2i(Vector2(), texture->get_size()));
|
||||
if (rect.size.x > 0 && rect.size.y > 0) {
|
||||
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
|
||||
base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the texture around the grid.
|
||||
Rect2i rect;
|
||||
|
||||
// Top.
|
||||
rect.position = Vector2i();
|
||||
rect.set_end(Vector2i(texture->get_size().x, margins.y));
|
||||
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
|
||||
base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
|
||||
|
||||
// Bottom
|
||||
int bottom_border = margins.y + (grid_size.y * texture_region_size.y);
|
||||
int bottom_border = margins.y + (grid_size.y * (texture_region_size.y + separation.y));
|
||||
if (bottom_border < texture->get_size().y) {
|
||||
rect.position = Vector2i(0, bottom_border);
|
||||
rect.set_end(texture->get_size());
|
||||
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
|
||||
base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
|
||||
}
|
||||
|
||||
// Left
|
||||
rect.position = Vector2i(0, margins.y);
|
||||
rect.set_end(Vector2i(margins.x, margins.y + (grid_size.y * texture_region_size.y)));
|
||||
rect.set_end(Vector2i(margins.x, margins.y + (grid_size.y * (texture_region_size.y + separation.y))));
|
||||
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
|
||||
base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
|
||||
|
||||
// Right.
|
||||
int right_border = margins.x + (grid_size.x * texture_region_size.x);
|
||||
int right_border = margins.x + (grid_size.x * (texture_region_size.x + separation.x));
|
||||
if (right_border < texture->get_size().x) {
|
||||
rect.position = Vector2i(right_border, margins.y);
|
||||
rect.set_end(Vector2i(texture->get_size().x, margins.y + (grid_size.y * texture_region_size.y)));
|
||||
rect.set_end(Vector2i(texture->get_size().x, margins.y + (grid_size.y * (texture_region_size.y + separation.y))));
|
||||
base_tiles_draw->draw_texture_rect_region(texture, rect, rect);
|
||||
base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5));
|
||||
}
|
||||
|
||||
// Draw actual tiles, using their properties (modulation, etc...)
|
||||
|
@ -258,12 +262,30 @@ void TileAtlasView::_draw_base_tiles() {
|
|||
|
||||
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));
|
||||
Rect2i base_frame_rect = tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame);
|
||||
Vector2i offset_pos = base_frame_rect.get_center() + 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, frame);
|
||||
|
||||
// Draw, the texture in the separation areas
|
||||
if (separation.x > 0) {
|
||||
Rect2i right_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(base_frame_rect.size.x, 0), Vector2i(separation.x, base_frame_rect.size.y));
|
||||
right_sep_rect = right_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
|
||||
if (right_sep_rect.size.x > 0 && right_sep_rect.size.y > 0) {
|
||||
base_tiles_draw->draw_texture_rect_region(texture, right_sep_rect, right_sep_rect);
|
||||
base_tiles_draw->draw_rect(right_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
if (separation.y > 0) {
|
||||
Rect2i bottom_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(0, base_frame_rect.size.y), Vector2i(base_frame_rect.size.x + separation.x, separation.y));
|
||||
bottom_sep_rect = bottom_sep_rect.intersection(Rect2i(Vector2(), texture->get_size()));
|
||||
if (bottom_sep_rect.size.x > 0 && bottom_sep_rect.size.y > 0) {
|
||||
base_tiles_draw->draw_texture_rect_region(texture, bottom_sep_rect, bottom_sep_rect);
|
||||
base_tiles_draw->draw_rect(bottom_sep_rect, Color(0.0, 0.0, 0.0, 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,30 +321,6 @@ void TileAtlasView::_draw_base_tiles_texture_grid() {
|
|||
}
|
||||
}
|
||||
|
||||
void TileAtlasView::_draw_base_tiles_dark() {
|
||||
Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
|
||||
if (texture.is_valid()) {
|
||||
Vector2i margins = tile_set_atlas_source->get_margins();
|
||||
Vector2i separation = tile_set_atlas_source->get_separation();
|
||||
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
|
||||
|
||||
Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
|
||||
|
||||
// Draw each tile texture region.
|
||||
for (int x = 0; x < grid_size.x; x++) {
|
||||
for (int y = 0; y < grid_size.y; y++) {
|
||||
Vector2i origin = margins + (Vector2i(x, y) * (texture_region_size + separation));
|
||||
Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
|
||||
|
||||
if (base_tile_coords == TileSetSource::INVALID_ATLAS_COORDS) {
|
||||
// Draw the grid.
|
||||
base_tiles_dark->draw_rect(Rect2i(origin, texture_region_size), Color(0.0, 0.0, 0.0, 0.5), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileAtlasView::_draw_base_tiles_shape_grid() {
|
||||
// Draw the shapes.
|
||||
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
|
||||
|
@ -453,7 +451,6 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
|
|||
base_tiles_draw->update();
|
||||
base_tiles_texture_grid->update();
|
||||
base_tiles_shape_grid->update();
|
||||
base_tiles_dark->update();
|
||||
alternatives_draw->update();
|
||||
background_left->update();
|
||||
background_right->update();
|
||||
|
@ -544,7 +541,6 @@ void TileAtlasView::update() {
|
|||
base_tiles_draw->update();
|
||||
base_tiles_texture_grid->update();
|
||||
base_tiles_shape_grid->update();
|
||||
base_tiles_dark->update();
|
||||
alternatives_draw->update();
|
||||
background_left->update();
|
||||
background_right->update();
|
||||
|
@ -660,12 +656,6 @@ TileAtlasView::TileAtlasView() {
|
|||
base_tiles_shape_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_shape_grid));
|
||||
base_tiles_drawing_root->add_child(base_tiles_shape_grid);
|
||||
|
||||
base_tiles_dark = memnew(Control);
|
||||
base_tiles_dark->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
|
||||
base_tiles_dark->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
|
||||
base_tiles_dark->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_dark));
|
||||
base_tiles_drawing_root->add_child(base_tiles_dark);
|
||||
|
||||
// Alternative tiles.
|
||||
Label *alternative_tiles_label = memnew(Label);
|
||||
alternative_tiles_label->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
|
||||
|
|
|
@ -93,9 +93,6 @@ private:
|
|||
Control *base_tiles_shape_grid;
|
||||
void _draw_base_tiles_shape_grid();
|
||||
|
||||
Control *base_tiles_dark;
|
||||
void _draw_base_tiles_dark();
|
||||
|
||||
Size2i _compute_base_tiles_control_size();
|
||||
|
||||
// Right side.
|
||||
|
@ -124,7 +121,6 @@ public:
|
|||
|
||||
// Left side.
|
||||
void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); };
|
||||
void set_dark_visible(bool p_visible) { base_tiles_dark->set_visible(p_visible); };
|
||||
void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); };
|
||||
|
||||
Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos) const;
|
||||
|
|
|
@ -520,9 +520,6 @@ void TileSetAtlasSourceEditor::_update_tile_id_label() {
|
|||
void TileSetAtlasSourceEditor::_update_source_inspector() {
|
||||
// Update the proxy object.
|
||||
atlas_source_proxy_object->edit(tile_set, tile_set_atlas_source, tile_set_atlas_source_id);
|
||||
|
||||
// Update the "clear outside texture" button.
|
||||
tool_advanced_menu_buttom->get_popup()->set_item_disabled(0, !tile_set_atlas_source->has_tiles_outside_texture());
|
||||
}
|
||||
|
||||
void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() {
|
||||
|
@ -1600,9 +1597,6 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) {
|
|||
undo_redo->commit_action();
|
||||
_update_tile_id_label();
|
||||
} break;
|
||||
case ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE: {
|
||||
tile_set_atlas_source->clear_tiles_outside_texture();
|
||||
} break;
|
||||
case ADVANCED_AUTO_CREATE_TILES: {
|
||||
_auto_create_tiles();
|
||||
} break;
|
||||
|
@ -2035,30 +2029,66 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
|
|||
|
||||
#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
|
||||
|
||||
AtlasTileProxyObject *tile_data = Object::cast_to<AtlasTileProxyObject>(p_edited);
|
||||
if (tile_data) {
|
||||
undo_redo->start_force_keep_in_merge_ends();
|
||||
AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited);
|
||||
if (tile_data_proxy) {
|
||||
Vector<String> components = String(p_property).split("/", true, 2);
|
||||
if (components.size() == 2 && components[1] == "polygons_count") {
|
||||
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
|
||||
int new_polygons_count = p_new_value;
|
||||
int old_polygons_count = tile_data->get(vformat("physics_layer_%d/polygons_count", layer_index));
|
||||
int old_polygons_count = tile_data_proxy->get(vformat("physics_layer_%d/polygons_count", layer_index));
|
||||
if (new_polygons_count < old_polygons_count) {
|
||||
for (int i = new_polygons_count - 1; i < old_polygons_count; i++) {
|
||||
ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/points", layer_index, i));
|
||||
ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, i));
|
||||
ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way_margin", layer_index, i));
|
||||
ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/points", layer_index, i));
|
||||
ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, i));
|
||||
ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/one_way_margin", layer_index, i));
|
||||
}
|
||||
}
|
||||
} else if (p_property == "terrain_set") {
|
||||
int current_terrain_set = tile_data->get("terrain_set");
|
||||
int current_terrain_set = tile_data_proxy->get("terrain_set");
|
||||
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
|
||||
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
|
||||
if (tile_set->is_valid_peering_bit_terrain(current_terrain_set, bit)) {
|
||||
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
|
||||
ADD_UNDO(tile_data_proxy, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TileSetAtlasSourceProxyObject *atlas_source_proxy = Object::cast_to<TileSetAtlasSourceProxyObject>(p_edited);
|
||||
if (atlas_source_proxy) {
|
||||
TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited();
|
||||
ERR_FAIL_COND(!atlas_source);
|
||||
|
||||
PackedVector2Array arr;
|
||||
if (p_property == "texture") {
|
||||
arr = atlas_source->get_tiles_to_be_removed_on_change(p_new_value, atlas_source->get_margins(), atlas_source->get_separation(), atlas_source->get_texture_region_size());
|
||||
} else if (p_property == "margins") {
|
||||
arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), p_new_value, atlas_source->get_separation(), atlas_source->get_texture_region_size());
|
||||
} else if (p_property == "separation") {
|
||||
arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), atlas_source->get_margins(), p_new_value, atlas_source->get_texture_region_size());
|
||||
} else if (p_property == "texture_region_size") {
|
||||
arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), atlas_source->get_margins(), atlas_source->get_separation(), p_new_value);
|
||||
}
|
||||
|
||||
if (!arr.is_empty()) {
|
||||
// Get all properties assigned to a tile.
|
||||
List<PropertyInfo> properties;
|
||||
atlas_source->get_property_list(&properties);
|
||||
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
Vector2i coords = arr[i];
|
||||
String prefix = vformat("%d:%d/", coords.x, coords.y);
|
||||
for (PropertyInfo pi : properties) {
|
||||
if (pi.name.begins_with(prefix)) {
|
||||
ADD_UNDO(atlas_source, pi.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
undo_redo->end_force_keep_in_merge_ends();
|
||||
|
||||
#undef ADD_UNDO
|
||||
}
|
||||
|
||||
|
@ -2406,8 +2436,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
|
|||
|
||||
tool_advanced_menu_buttom = memnew(MenuButton);
|
||||
tool_advanced_menu_buttom->set_flat(true);
|
||||
tool_advanced_menu_buttom->get_popup()->add_item(TTR("Cleanup Tiles Outside Texture"), ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE);
|
||||
tool_advanced_menu_buttom->get_popup()->set_item_disabled(0, true);
|
||||
tool_advanced_menu_buttom->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES);
|
||||
tool_advanced_menu_buttom->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES);
|
||||
tool_advanced_menu_buttom->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
|
||||
|
@ -2481,6 +2509,8 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
|
|||
tile_atlas_view_missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
tile_atlas_view_missing_source_label->hide();
|
||||
right_panel->add_child(tile_atlas_view_missing_source_label);
|
||||
|
||||
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetAtlasSourceEditor::_undo_redo_inspector_callback));
|
||||
}
|
||||
|
||||
TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() {
|
||||
|
|
|
@ -78,6 +78,7 @@ private:
|
|||
int get_id();
|
||||
|
||||
void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id);
|
||||
TileSetAtlasSource *get_edited() { return tile_set_atlas_source; };
|
||||
};
|
||||
|
||||
// -- Proxy object for a tile, needed by the inspector --
|
||||
|
@ -189,7 +190,6 @@ private:
|
|||
TILE_CREATE_ALTERNATIVE,
|
||||
TILE_DELETE,
|
||||
|
||||
ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE,
|
||||
ADVANCED_AUTO_CREATE_TILES,
|
||||
ADVANCED_AUTO_REMOVE_TILES,
|
||||
};
|
||||
|
|
|
@ -3066,6 +3066,7 @@ void TileSetAtlasSource::reset_state() {
|
|||
void TileSetAtlasSource::set_texture(Ref<Texture2D> p_texture) {
|
||||
texture = p_texture;
|
||||
|
||||
_clear_tiles_outside_texture();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
|
@ -3081,6 +3082,7 @@ void TileSetAtlasSource::set_margins(Vector2i p_margins) {
|
|||
margins = p_margins;
|
||||
}
|
||||
|
||||
_clear_tiles_outside_texture();
|
||||
emit_changed();
|
||||
}
|
||||
Vector2i TileSetAtlasSource::get_margins() const {
|
||||
|
@ -3095,6 +3097,7 @@ void TileSetAtlasSource::set_separation(Vector2i p_separation) {
|
|||
separation = p_separation;
|
||||
}
|
||||
|
||||
_clear_tiles_outside_texture();
|
||||
emit_changed();
|
||||
}
|
||||
Vector2i TileSetAtlasSource::get_separation() const {
|
||||
|
@ -3109,6 +3112,7 @@ void TileSetAtlasSource::set_texture_region_size(Vector2i p_tile_size) {
|
|||
texture_region_size = p_tile_size;
|
||||
}
|
||||
|
||||
_clear_tiles_outside_texture();
|
||||
emit_changed();
|
||||
}
|
||||
Vector2i TileSetAtlasSource::get_texture_region_size() const {
|
||||
|
@ -3354,7 +3358,7 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector
|
|||
ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0);
|
||||
|
||||
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.");
|
||||
ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile. The tile is outside the texture or tiles are already present in the space the tile would cover.");
|
||||
|
||||
// Initialize the tile data.
|
||||
TileAlternativesData tad;
|
||||
|
@ -3552,9 +3556,7 @@ bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_s
|
|||
return false;
|
||||
}
|
||||
if (coords.x >= atlas_grid_size.x || coords.y >= atlas_grid_size.y) {
|
||||
if (!(_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] == p_ignored_tile)) {
|
||||
return false; // Only accept tiles outside the atlas if they are part of the ignored tile.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3562,6 +3564,33 @@ bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_s
|
|||
return true;
|
||||
}
|
||||
|
||||
PackedVector2Array TileSetAtlasSource::get_tiles_to_be_removed_on_change(Ref<Texture2D> p_texture, Vector2i p_margins, Vector2i p_separation, Vector2i p_texture_region_size) {
|
||||
// Compute the new atlas grid size.
|
||||
Size2 new_grid_size;
|
||||
if (p_texture.is_valid()) {
|
||||
Size2i valid_area = p_texture->get_size() - p_margins;
|
||||
|
||||
// Compute the number of valid tiles in the tiles atlas
|
||||
if (valid_area.x >= p_texture_region_size.x && valid_area.y >= p_texture_region_size.y) {
|
||||
valid_area -= p_texture_region_size;
|
||||
new_grid_size = Size2i(1, 1) + valid_area / (p_texture_region_size + p_separation);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<Vector2> output;
|
||||
for (KeyValue<Vector2i, TileAlternativesData> &E : tiles) {
|
||||
for (unsigned int frame = 0; frame < E.value.animation_frames_durations.size(); frame++) {
|
||||
Vector2i frame_coords = E.key + (E.value.size_in_atlas + E.value.animation_separation) * ((E.value.animation_columns > 0) ? Vector2i(frame % E.value.animation_columns, frame / E.value.animation_columns) : Vector2i(frame, 0));
|
||||
frame_coords += E.value.size_in_atlas;
|
||||
if (frame_coords.x > new_grid_size.x || frame_coords.y > new_grid_size.y) {
|
||||
output.push_back(E.key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
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());
|
||||
|
@ -3626,34 +3655,6 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_
|
|||
emit_signal(SNAME("changed"));
|
||||
}
|
||||
|
||||
bool TileSetAtlasSource::has_tiles_outside_texture() {
|
||||
Vector2i grid_size = get_atlas_grid_size();
|
||||
Vector<Vector2i> to_remove;
|
||||
|
||||
for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
|
||||
if (E.key.x >= grid_size.x || E.key.y >= grid_size.y) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TileSetAtlasSource::clear_tiles_outside_texture() {
|
||||
Vector2i grid_size = get_atlas_grid_size();
|
||||
Vector<Vector2i> to_remove;
|
||||
|
||||
for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
|
||||
if (E.key.x >= grid_size.x || E.key.y >= grid_size.y) {
|
||||
to_remove.append(E.key);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < to_remove.size(); i++) {
|
||||
remove_tile(to_remove[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override) {
|
||||
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
|
||||
ERR_FAIL_COND_V_MSG(p_alternative_id_override >= 0 && tiles[p_atlas_coords].alternatives.has(p_alternative_id_override), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("Cannot create alternative tile. Another alternative exists with id %d.", p_alternative_id_override));
|
||||
|
@ -3754,7 +3755,7 @@ void TileSetAtlasSource::_bind_methods() {
|
|||
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_tiles_to_be_removed_on_change", "texture", "margins", "separation", "texture_region_size"), &TileSetAtlasSource::get_tiles_to_be_removed_on_change);
|
||||
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);
|
||||
|
@ -3779,8 +3780,6 @@ void TileSetAtlasSource::_bind_methods() {
|
|||
|
||||
// Helpers.
|
||||
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", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0));
|
||||
}
|
||||
|
||||
|
@ -3854,6 +3853,20 @@ void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) {
|
|||
}
|
||||
}
|
||||
|
||||
void TileSetAtlasSource::_clear_tiles_outside_texture() {
|
||||
LocalVector<Vector2i> to_remove;
|
||||
|
||||
for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
|
||||
if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) {
|
||||
to_remove.push_back(E.key);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < to_remove.size(); i++) {
|
||||
remove_tile(to_remove[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////// TileSetScenesCollectionSource //////////////////////////////////////
|
||||
|
||||
void TileSetScenesCollectionSource::_compute_next_alternative_id() {
|
||||
|
|
|
@ -479,8 +479,10 @@ 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);
|
||||
void _create_coords_mapping_cache(Vector2i p_atlas_coords);
|
||||
|
||||
void _clear_tiles_outside_texture();
|
||||
|
||||
protected:
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
|
@ -534,7 +536,7 @@ public:
|
|||
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;
|
||||
|
||||
PackedVector2Array get_tiles_to_be_removed_on_change(Ref<Texture2D> p_texture, Vector2i p_margins, Vector2i p_separation, Vector2i p_texture_region_size);
|
||||
Vector2i get_tile_at_coords(Vector2i p_atlas_coords) const;
|
||||
|
||||
// Animation.
|
||||
|
@ -565,8 +567,6 @@ public:
|
|||
|
||||
// Helpers.
|
||||
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, int p_frame = 0) const;
|
||||
Vector2i get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue