Texture Region: Cache auto-slice information into the texture. Fixes #11503
This commit is contained in:
parent
12290c172a
commit
1f4a891a9c
|
@ -355,8 +355,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
|
|||
} else if (atlas_tex.is_valid()) {
|
||||
undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
|
||||
undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev);
|
||||
} else if (node_ninepatch) {
|
||||
// FIXME: Is this intentional?
|
||||
} else if (node_ninepatch) {
|
||||
undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect());
|
||||
undo_redo->add_undo_method(node_ninepatch, "set_region_rect", rect_prev);
|
||||
|
@ -521,6 +519,10 @@ void TextureRegionEditor::_set_snap_mode(int p_mode) {
|
|||
else
|
||||
hb_grid->hide();
|
||||
|
||||
if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
|
||||
_update_autoslice();
|
||||
}
|
||||
|
||||
edit_draw->update();
|
||||
}
|
||||
|
||||
|
@ -562,7 +564,8 @@ void TextureRegionEditor::_zoom_in() {
|
|||
}
|
||||
|
||||
void TextureRegionEditor::_zoom_reset() {
|
||||
if (draw_zoom == 1) return;
|
||||
if (draw_zoom == 1)
|
||||
return;
|
||||
draw_zoom = 1;
|
||||
edit_draw->update();
|
||||
}
|
||||
|
@ -585,25 +588,91 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) {
|
|||
atlas_tex->set_region(rect);
|
||||
}
|
||||
|
||||
void TextureRegionEditor::_update_autoslice() {
|
||||
autoslice_is_dirty = false;
|
||||
autoslice_cache.clear();
|
||||
|
||||
Ref<Texture> texture = NULL;
|
||||
if (node_sprite)
|
||||
texture = node_sprite->get_texture();
|
||||
else if (node_ninepatch)
|
||||
texture = node_ninepatch->get_texture();
|
||||
else if (obj_styleBox.is_valid())
|
||||
texture = obj_styleBox->get_texture();
|
||||
else if (atlas_tex.is_valid())
|
||||
texture = atlas_tex->get_atlas();
|
||||
|
||||
if (texture.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int y = 0; y < texture->get_height(); y++) {
|
||||
for (int x = 0; x < texture->get_width(); x++) {
|
||||
if (texture->is_pixel_opaque(x, y)) {
|
||||
bool found = false;
|
||||
for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
|
||||
Rect2 grown = E->get().grow(1.5);
|
||||
if (grown.has_point(Point2(x, y))) {
|
||||
E->get().expand_to(Point2(x, y));
|
||||
E->get().expand_to(Point2(x + 1, y + 1));
|
||||
x = E->get().position.x + E->get().size.x - 1;
|
||||
bool merged = true;
|
||||
while (merged) {
|
||||
merged = false;
|
||||
bool queue_erase = false;
|
||||
for (List<Rect2>::Element *F = autoslice_cache.front(); F; F = F->next()) {
|
||||
if (queue_erase) {
|
||||
autoslice_cache.erase(F->prev());
|
||||
queue_erase = false;
|
||||
}
|
||||
if (F == E)
|
||||
continue;
|
||||
if (E->get().grow(1).intersects(F->get())) {
|
||||
E->get().expand_to(F->get().position);
|
||||
E->get().expand_to(F->get().position + F->get().size);
|
||||
if (F->prev()) {
|
||||
F = F->prev();
|
||||
autoslice_cache.erase(F->next());
|
||||
} else {
|
||||
queue_erase = true;
|
||||
// Can't delete the first rect in the list.
|
||||
}
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
Rect2 new_rect(x, y, 1, 1);
|
||||
autoslice_cache.push_back(new_rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cache_map[texture->get_rid()] = autoslice_cache;
|
||||
}
|
||||
|
||||
void TextureRegionEditor::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_PROCESS: {
|
||||
if (node_sprite) {
|
||||
if (node_sprite->is_region()) {
|
||||
|
||||
set_process(false);
|
||||
EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
|
||||
}
|
||||
} else {
|
||||
set_process(false);
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_THEME_CHANGED:
|
||||
case NOTIFICATION_READY: {
|
||||
zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons"));
|
||||
zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons"));
|
||||
zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons"));
|
||||
} break;
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
|
||||
_update_autoslice();
|
||||
}
|
||||
} break;
|
||||
case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
|
||||
// This happens when the user leaves the Editor and returns,
|
||||
// he/she could have changed the textures, so the cache is cleared
|
||||
cache_map.clear();
|
||||
_edit_region();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,57 +778,15 @@ void TextureRegionEditor::_edit_region() {
|
|||
return;
|
||||
}
|
||||
|
||||
autoslice_cache.clear();
|
||||
Ref<Image> i;
|
||||
i.instance();
|
||||
if (i->load(texture->get_path()) == OK) {
|
||||
BitMap bm;
|
||||
bm.create_from_image_alpha(i);
|
||||
for (int y = 0; y < i->get_height(); y++) {
|
||||
for (int x = 0; x < i->get_width(); x++) {
|
||||
if (bm.get_bit(Point2(x, y))) {
|
||||
bool found = false;
|
||||
for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
|
||||
Rect2 grown = E->get().grow(1.5);
|
||||
if (grown.has_point(Point2(x, y))) {
|
||||
E->get().expand_to(Point2(x, y));
|
||||
E->get().expand_to(Point2(x + 1, y + 1));
|
||||
x = E->get().position.x + E->get().size.x - 1;
|
||||
bool merged = true;
|
||||
while (merged) {
|
||||
merged = false;
|
||||
bool queue_erase = false;
|
||||
for (List<Rect2>::Element *F = autoslice_cache.front(); F; F = F->next()) {
|
||||
if (queue_erase) {
|
||||
autoslice_cache.erase(F->prev());
|
||||
queue_erase = false;
|
||||
}
|
||||
if (F == E)
|
||||
continue;
|
||||
if (E->get().grow(1).intersects(F->get())) {
|
||||
E->get().expand_to(F->get().position);
|
||||
E->get().expand_to(F->get().position + F->get().size);
|
||||
if (F->prev()) {
|
||||
F = F->prev();
|
||||
autoslice_cache.erase(F->next());
|
||||
if (cache_map.has(texture->get_rid())) {
|
||||
autoslice_cache = cache_map[texture->get_rid()];
|
||||
autoslice_is_dirty = false;
|
||||
return;
|
||||
} else {
|
||||
queue_erase = true;
|
||||
//Can't delete the first rect in the list.
|
||||
}
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
Rect2 new_rect(x, y, 1, 1);
|
||||
autoslice_cache.push_back(new_rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_visible() && snap_mode == SNAP_AUTOSLICE) {
|
||||
_update_autoslice();
|
||||
} else {
|
||||
autoslice_is_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,9 @@ class TextureRegionEditor : public Control {
|
|||
Rect2 rect_prev;
|
||||
float prev_margin;
|
||||
int edited_margin;
|
||||
Map<RID, List<Rect2> > cache_map;
|
||||
List<Rect2> autoslice_cache;
|
||||
bool autoslice_is_dirty;
|
||||
|
||||
bool drag;
|
||||
bool creating;
|
||||
|
@ -110,6 +112,7 @@ class TextureRegionEditor : public Control {
|
|||
void _zoom_reset();
|
||||
void _zoom_out();
|
||||
void apply_rect(const Rect2 &rect);
|
||||
void _update_autoslice();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
Loading…
Reference in New Issue