Texture Region: Cache auto-slice information into the texture. Fixes #11503

This commit is contained in:
Mariano Suligoy 2017-12-24 16:00:30 -03:00 committed by Mariano Javier Suligoy
parent 12290c172a
commit 1f4a891a9c
2 changed files with 96 additions and 66 deletions

View File

@ -355,8 +355,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else if (atlas_tex.is_valid()) { } else if (atlas_tex.is_valid()) {
undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region()); 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); undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev);
} else if (node_ninepatch) {
// FIXME: Is this intentional?
} else if (node_ninepatch) { } else if (node_ninepatch) {
undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect()); 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); 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 else
hb_grid->hide(); hb_grid->hide();
if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
_update_autoslice();
}
edit_draw->update(); edit_draw->update();
} }
@ -562,7 +564,8 @@ void TextureRegionEditor::_zoom_in() {
} }
void TextureRegionEditor::_zoom_reset() { void TextureRegionEditor::_zoom_reset() {
if (draw_zoom == 1) return; if (draw_zoom == 1)
return;
draw_zoom = 1; draw_zoom = 1;
edit_draw->update(); edit_draw->update();
} }
@ -585,25 +588,91 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) {
atlas_tex->set_region(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) { void TextureRegionEditor::_notification(int p_what) {
switch (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: { case NOTIFICATION_READY: {
zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons")); zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons"));
zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons"));
zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons")); zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons"));
} break; } 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; return;
} }
autoslice_cache.clear(); if (cache_map.has(texture->get_rid())) {
Ref<Image> i; autoslice_cache = cache_map[texture->get_rid()];
i.instance(); autoslice_is_dirty = false;
if (i->load(texture->get_path()) == OK) { return;
BitMap bm; } else {
bm.create_from_image_alpha(i); if (is_visible() && snap_mode == SNAP_AUTOSLICE) {
for (int y = 0; y < i->get_height(); y++) { _update_autoslice();
for (int x = 0; x < i->get_width(); x++) { } else {
if (bm.get_bit(Point2(x, y))) { autoslice_is_dirty = true;
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);
}
}
}
} }
} }

View File

@ -92,7 +92,9 @@ class TextureRegionEditor : public Control {
Rect2 rect_prev; Rect2 rect_prev;
float prev_margin; float prev_margin;
int edited_margin; int edited_margin;
Map<RID, List<Rect2> > cache_map;
List<Rect2> autoslice_cache; List<Rect2> autoslice_cache;
bool autoslice_is_dirty;
bool drag; bool drag;
bool creating; bool creating;
@ -110,6 +112,7 @@ class TextureRegionEditor : public Control {
void _zoom_reset(); void _zoom_reset();
void _zoom_out(); void _zoom_out();
void apply_rect(const Rect2 &rect); void apply_rect(const Rect2 &rect);
void _update_autoslice();
protected: protected:
void _notification(int p_what); void _notification(int p_what);