ソースを参照

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

Mariano Suligoy 7 年 前
コミット
1f4a891a9c

+ 92 - 65
editor/plugins/texture_region_editor_plugin.cpp

@@ -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::_notification(int p_what) {
-	switch (p_what) {
-		case NOTIFICATION_PROCESS: {
-			if (node_sprite) {
-				if (node_sprite->is_region()) {
+void TextureRegionEditor::_update_autoslice() {
+	autoslice_is_dirty = false;
+	autoslice_cache.clear();
 
-					set_process(false);
-					EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+	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);
 				}
-			} else {
-				set_process(false);
 			}
-		} break;
-		case NOTIFICATION_THEME_CHANGED:
+		}
+	}
+	cache_map[texture->get_rid()] = autoslice_cache;
+}
+
+void TextureRegionEditor::_notification(int p_what) {
+	switch (p_what) {
 		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());
-										} 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 (cache_map.has(texture->get_rid())) {
+		autoslice_cache = cache_map[texture->get_rid()];
+		autoslice_is_dirty = false;
+		return;
+	} else {
+		if (is_visible() && snap_mode == SNAP_AUTOSLICE) {
+			_update_autoslice();
+		} else {
+			autoslice_is_dirty = true;
 		}
 	}
 

+ 3 - 0
editor/plugins/texture_region_editor_plugin.h

@@ -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);