Tilemap Editor: Bucket fill
This commit is contained in:
parent
9de53c98a0
commit
aba9729ba7
2 changed files with 136 additions and 18 deletions
|
@ -58,6 +58,12 @@ void TileMapEditor::_menu_option(int p_option) {
|
||||||
|
|
||||||
switch(p_option) {
|
switch(p_option) {
|
||||||
|
|
||||||
|
case OPTION_BUCKET_FILL: {
|
||||||
|
|
||||||
|
tool=TOOL_BUCKET;
|
||||||
|
|
||||||
|
canvas_item_editor->update();
|
||||||
|
} break;
|
||||||
case OPTION_PICK_TILE: {
|
case OPTION_PICK_TILE: {
|
||||||
|
|
||||||
tool=TOOL_PICKING;
|
tool=TOOL_PICKING;
|
||||||
|
@ -270,6 +276,84 @@ void TileMapEditor::_pick_tile(const Point2& p_pos) {
|
||||||
canvas_item_editor->update();
|
canvas_item_editor->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BUCKET_FILL_LIMIT 50
|
||||||
|
|
||||||
|
DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start) {
|
||||||
|
|
||||||
|
if (node->get_cell(p_start.x, p_start.y) != TileMap::INVALID_CELL)
|
||||||
|
return DVector<Vector2>();
|
||||||
|
|
||||||
|
int id = get_selected_tile();
|
||||||
|
|
||||||
|
if (id == TileMap::INVALID_CELL)
|
||||||
|
return DVector<Vector2>();
|
||||||
|
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
DVector<Vector2> points;
|
||||||
|
points.resize(Math::pow(BUCKET_FILL_LIMIT*2, 2));
|
||||||
|
|
||||||
|
List<Point2i> queue;
|
||||||
|
queue.push_back(p_start);
|
||||||
|
|
||||||
|
DVector<Vector2>::Write pw = points.write();
|
||||||
|
|
||||||
|
while (queue.size()) {
|
||||||
|
|
||||||
|
Point2i n = queue.front()->get();
|
||||||
|
queue.pop_front();
|
||||||
|
|
||||||
|
if (ABS(n.x - p_start.x) > BUCKET_FILL_LIMIT || ABS(n.y - p_start.y) > BUCKET_FILL_LIMIT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (node->get_cell(n.x, n.y) == TileMap::INVALID_CELL) {
|
||||||
|
|
||||||
|
node->set_cellv(n, id, flip_h, flip_v, transpose);
|
||||||
|
|
||||||
|
pw[++len] = n;
|
||||||
|
|
||||||
|
queue.push_back(n + Point2i(0, 1));
|
||||||
|
queue.push_back(n + Point2i(0, -1));
|
||||||
|
queue.push_back(n + Point2i(1, 0));
|
||||||
|
queue.push_back(n + Point2i(-1, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pw = DVector<Vector2>::Write();
|
||||||
|
points.resize(len);
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BUCKET_FILL_LIMIT
|
||||||
|
|
||||||
|
void TileMapEditor::_fill_points(const DVector<Vector2> p_points, const Dictionary& p_op) {
|
||||||
|
|
||||||
|
int len = p_points.size();
|
||||||
|
DVector<Vector2>::Read pr = p_points.read();
|
||||||
|
|
||||||
|
int id = p_op["id"];
|
||||||
|
bool xf = p_op["flip_h"];
|
||||||
|
bool yf = p_op["flip_v"];
|
||||||
|
bool tr = p_op["transpose"];
|
||||||
|
|
||||||
|
for (int i=0;i<len;i++) {
|
||||||
|
|
||||||
|
_set_cell(pr[i], id, xf, yf, tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TileMapEditor::_erase_points(const DVector<Vector2> p_points) {
|
||||||
|
|
||||||
|
int len = p_points.size();
|
||||||
|
DVector<Vector2>::Read pr = p_points.read();
|
||||||
|
|
||||||
|
for (int i=0;i<len;i++) {
|
||||||
|
|
||||||
|
_set_cell(pr[i], TileMap::INVALID_CELL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TileMapEditor::_select(const Point2i& p_from, const Point2i& p_to) {
|
void TileMapEditor::_select(const Point2i& p_from, const Point2i& p_to) {
|
||||||
|
|
||||||
Point2i begin=p_from;
|
Point2i begin=p_from;
|
||||||
|
@ -514,24 +598,10 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tool==TOOL_DUPLICATING) {
|
if (tool!=TOOL_NONE) {
|
||||||
|
|
||||||
Point2 ofs = over_tile-rectangle.pos;
|
|
||||||
|
|
||||||
undo_redo->create_action("Duplicate");
|
|
||||||
for (List<TileData>::Element *E=copydata.front();E;E=E->next()) {
|
|
||||||
|
|
||||||
_set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,E->get().transpose,true);
|
|
||||||
}
|
|
||||||
undo_redo->commit_action();
|
|
||||||
|
|
||||||
tool=TOOL_NONE;
|
|
||||||
copydata.clear();
|
|
||||||
|
|
||||||
canvas_item_editor->update();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (tool!=TOOL_NONE) {
|
if (tool!=TOOL_NONE) {
|
||||||
|
@ -585,9 +655,44 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
|
||||||
|
|
||||||
canvas_item_editor->update();
|
canvas_item_editor->update();
|
||||||
}
|
}
|
||||||
|
} else if (tool==TOOL_DUPLICATING) {
|
||||||
|
|
||||||
|
Point2 ofs = over_tile-rectangle.pos;
|
||||||
|
|
||||||
|
undo_redo->create_action("Duplicate");
|
||||||
|
for (List<TileData>::Element *E=copydata.front();E;E=E->next()) {
|
||||||
|
|
||||||
|
_set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,E->get().transpose,true);
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
|
|
||||||
|
copydata.clear();
|
||||||
|
|
||||||
|
canvas_item_editor->update();
|
||||||
|
|
||||||
} else if (tool==TOOL_SELECTING) {
|
} else if (tool==TOOL_SELECTING) {
|
||||||
|
|
||||||
canvas_item_editor->update();
|
canvas_item_editor->update();
|
||||||
|
|
||||||
|
} else if (tool==TOOL_BUCKET) {
|
||||||
|
|
||||||
|
DVector<Vector2> points = _bucket_fill(over_tile);
|
||||||
|
|
||||||
|
if (points.size() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Dictionary op;
|
||||||
|
op["id"] = get_selected_tile();
|
||||||
|
op["flip_h"] = flip_h;
|
||||||
|
op["flip_v"] = flip_v;
|
||||||
|
op["transpose"] = transpose;
|
||||||
|
|
||||||
|
undo_redo->create_action("Bucket Fill");
|
||||||
|
|
||||||
|
undo_redo->add_do_method(this, "_fill_points", points, op);
|
||||||
|
undo_redo->add_undo_method(this, "_erase_points", points);
|
||||||
|
|
||||||
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
|
|
||||||
tool=TOOL_NONE;
|
tool=TOOL_NONE;
|
||||||
|
@ -1011,7 +1116,7 @@ void TileMapEditor::_canvas_draw() {
|
||||||
canvas_item_editor->draw_line(endpoints[i],endpoints[(i+1)%4],col,2);
|
canvas_item_editor->draw_line(endpoints[i],endpoints[(i+1)%4],col,2);
|
||||||
|
|
||||||
|
|
||||||
if (tool==TOOL_SELECTING || tool==TOOL_PICKING) {
|
if (tool==TOOL_SELECTING || tool==TOOL_PICKING || tool==TOOL_BUCKET) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1148,6 +1253,9 @@ void TileMapEditor::_bind_methods() {
|
||||||
ObjectTypeDB::bind_method(_MD("_canvas_mouse_exit"),&TileMapEditor::_canvas_mouse_exit);
|
ObjectTypeDB::bind_method(_MD("_canvas_mouse_exit"),&TileMapEditor::_canvas_mouse_exit);
|
||||||
ObjectTypeDB::bind_method(_MD("_tileset_settings_changed"),&TileMapEditor::_tileset_settings_changed);
|
ObjectTypeDB::bind_method(_MD("_tileset_settings_changed"),&TileMapEditor::_tileset_settings_changed);
|
||||||
ObjectTypeDB::bind_method(_MD("_update_transform_buttons"),&TileMapEditor::_update_transform_buttons);
|
ObjectTypeDB::bind_method(_MD("_update_transform_buttons"),&TileMapEditor::_update_transform_buttons);
|
||||||
|
|
||||||
|
ObjectTypeDB::bind_method(_MD("_fill_points"),&TileMapEditor::_fill_points);
|
||||||
|
ObjectTypeDB::bind_method(_MD("_erase_points"),&TileMapEditor::_erase_points);
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i& p_pos)
|
TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i& p_pos)
|
||||||
|
@ -1242,6 +1350,8 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
|
||||||
|
|
||||||
PopupMenu *p = options->get_popup();
|
PopupMenu *p = options->get_popup();
|
||||||
|
|
||||||
|
p->add_item("Bucket Fill", OPTION_BUCKET_FILL);
|
||||||
|
p->add_separator();
|
||||||
p->add_item("Pick Tile", OPTION_PICK_TILE, KEY_CONTROL);
|
p->add_item("Pick Tile", OPTION_PICK_TILE, KEY_CONTROL);
|
||||||
p->add_separator();
|
p->add_separator();
|
||||||
p->add_item("Select", OPTION_SELECT, KEY_MASK_SHIFT+KEY_B);
|
p->add_item("Select", OPTION_SELECT, KEY_MASK_SHIFT+KEY_B);
|
||||||
|
|
|
@ -55,12 +55,14 @@ class TileMapEditor : public VBoxContainer {
|
||||||
TOOL_LINE_PAINT,
|
TOOL_LINE_PAINT,
|
||||||
TOOL_LINE_ERASE,
|
TOOL_LINE_ERASE,
|
||||||
TOOL_SELECTING,
|
TOOL_SELECTING,
|
||||||
|
TOOL_BUCKET,
|
||||||
|
TOOL_PICKING,
|
||||||
TOOL_DUPLICATING,
|
TOOL_DUPLICATING,
|
||||||
TOOL_PICKING
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Options {
|
enum Options {
|
||||||
|
|
||||||
|
OPTION_BUCKET_FILL,
|
||||||
OPTION_PICK_TILE,
|
OPTION_PICK_TILE,
|
||||||
OPTION_SELECT,
|
OPTION_SELECT,
|
||||||
OPTION_DUPLICATE,
|
OPTION_DUPLICATE,
|
||||||
|
@ -123,6 +125,12 @@ class TileMapEditor : public VBoxContainer {
|
||||||
List<TileData> copydata;
|
List<TileData> copydata;
|
||||||
|
|
||||||
void _pick_tile(const Point2& p_pos);
|
void _pick_tile(const Point2& p_pos);
|
||||||
|
|
||||||
|
DVector<Vector2> _bucket_fill(const Point2i& p_start);
|
||||||
|
|
||||||
|
void _fill_points(const DVector<Vector2> p_points, const Dictionary& p_op);
|
||||||
|
void _erase_points(const DVector<Vector2> p_points);
|
||||||
|
|
||||||
void _select(const Point2i& p_from, const Point2i& p_to);
|
void _select(const Point2i& p_from, const Point2i& p_to);
|
||||||
|
|
||||||
void _draw_cell(int p_cell, const Point2i& p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Matrix32& p_xform);
|
void _draw_cell(int p_cell, const Point2i& p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Matrix32& p_xform);
|
||||||
|
|
Loading…
Reference in a new issue