package tk.amberide.ide.gui.editor.map.tool;
import tk.amberide.engine.data.map.Layer;
import tk.amberide.engine.data.map.Tile;
import tk.amberide.ide.data.res.Tileset;
import tk.amberide.engine.gl.camera.EulerCamera;
import tk.amberide.ide.gui.editor.map.MapContext;
import java.awt.Point;
import java.util.HashSet;
import java.util.Stack;
/**
*
* @author Tudor
*/
public class FillTool extends BrushTool {
public FillTool(MapContext context, EulerCamera camera) {
super(context, camera);
}
protected class FloodFiller {
private final FillTool tool;
private final Point start;
private final Layer layer;
private HashSet<Point> toFill = new HashSet<Point>();
int minX, minY, width, height, z;
Tileset.TileSprite[][] toFind;
public FloodFiller(FillTool tool, Point start, int z) {
this.tool = tool;
this.start = start;
this.z = z;
minX = start.x;
minY = start.y;
width = tool.context.tileSelection.length;
height = tool.context.tileSelection[0].length;
layer = context.map.getLayer(context.layer);
toFind = new Tileset.TileSprite[width][height];
for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)
toFind[x][y] = tool.spriteAt(start.x + x, start.y + y, z);
}
public void buildList() {
Stack<Point> toVisit = new Stack<Point>();
toVisit.push(start);
while (!toVisit.empty()) {
Point point = toVisit.pop();
if (!tool.isInBounds(point.x, point.y))
continue;
if (tool.spriteAt(point.x, point.y, z) != toFind[((start.x - point.x) % width + width) % width][((start.y - point.y) % height + height) % height])
continue;
if (!toFill.add(point))
continue;
if (point.x < minX)
minX = point.x;
if (point.y < minY)
minY = point.y;
toVisit.push(new Point(point.x - 1, point.y));
toVisit.push(new Point(point.x, point.y + 1));
toVisit.push(new Point(point.x + 1, point.y));
toVisit.push(new Point(point.x, point.y - 1));
}
}
public boolean fill() {
boolean modified = false;
for (Point point : toFill) {
int x = point.x, y = point.y;
Tileset.TileSprite sprite = context.tileSelection[(x - minX) % width][ (y - minY) % height];
if (!modified) {
Tile old = layer.getTile(x, y, 0);
modified = old == null || !sprite.equals(old.getSprite());
}
layer.setTile(x, y, z, new Tile(sprite, tool.camera.getFacingDirection()));
}
return modified;
}
}
public boolean apply(int x, int y, int z) {
FloodFiller filler = new FloodFiller(this, new Point(x, y), z);
filler.buildList();
return filler.fill();
}
private Tileset.TileSprite spriteAt(int x, int y, int z) {
if (isInBounds(x, y)) {
Tile tile = context.map.getLayer(context.layer).getTile(x, y, z);
return tile != null ? tile.getSprite() : Tileset.TileSprite.NULL_SPRITE;
}
return null;
}
}