Make flood fill respect whole metatile selection, including smart path. Smart path is now a checkbox
This commit is contained in:
parent
aafe258842
commit
64095821af
7 changed files with 175 additions and 49 deletions
159
editor.cpp
159
editor.cpp
|
@ -882,9 +882,6 @@ void MetatilesPixmapItem::updateSelection(QPointF pos, Qt::MouseButton button) {
|
||||||
map->paint_tile_index = baseTileY * 8 + baseTileX;
|
map->paint_tile_index = baseTileY * 8 + baseTileX;
|
||||||
map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
|
map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
|
||||||
map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1;
|
map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1;
|
||||||
map->smart_paths_enabled = button == Qt::RightButton
|
|
||||||
&& map->paint_tile_width == 3
|
|
||||||
&& map->paint_tile_height == 3;
|
|
||||||
emit map->paintTileChanged(map);
|
emit map->paintTileChanged(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1032,7 +1029,7 @@ void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
|
||||||
int x = (int)(pos.x()) / 16;
|
int x = (int)(pos.x()) / 16;
|
||||||
int y = (int)(pos.y()) / 16;
|
int y = (int)(pos.y()) / 16;
|
||||||
|
|
||||||
if (map->smart_paths_enabled) {
|
if (map->smart_paths_enabled && map->paint_tile_width == 3 && map->paint_tile_height == 3) {
|
||||||
paintSmartPath(x, y);
|
paintSmartPath(x, y);
|
||||||
} else {
|
} else {
|
||||||
paintNormal(x, y);
|
paintNormal(x, y);
|
||||||
|
@ -1160,11 +1157,163 @@ void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
|
||||||
QPointF pos = event->pos();
|
QPointF pos = event->pos();
|
||||||
int x = (int)(pos.x()) / 16;
|
int x = (int)(pos.x()) / 16;
|
||||||
int y = (int)(pos.y()) / 16;
|
int y = (int)(pos.y()) / 16;
|
||||||
map->floodFill(x, y, map->getSelectedBlockIndex(map->paint_tile_index));
|
Block *block = map->getBlock(x, y);
|
||||||
|
int tile = map->getSelectedBlockIndex(map->paint_tile_index);
|
||||||
|
if (block && block->tile != tile) {
|
||||||
|
if (map->smart_paths_enabled && map->paint_tile_width == 3 && map->paint_tile_height == 3)
|
||||||
|
this->_floodFillSmartPath(x, y);
|
||||||
|
else
|
||||||
|
this->_floodFill(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
|
||||||
|
map->commit();
|
||||||
|
}
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapPixmapItem::_floodFill(int initialX, int initialY) {
|
||||||
|
QList<QPoint> todo;
|
||||||
|
todo.append(QPoint(initialX, initialY));
|
||||||
|
while (todo.length()) {
|
||||||
|
QPoint point = todo.takeAt(0);
|
||||||
|
int x = point.x();
|
||||||
|
int y = point.y();
|
||||||
|
|
||||||
|
Block *block = map->getBlock(x, y);
|
||||||
|
if (block == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xDiff = x - initialX;
|
||||||
|
int yDiff = y - initialY;
|
||||||
|
int i = xDiff % map->paint_tile_width;
|
||||||
|
int j = yDiff % map->paint_tile_height;
|
||||||
|
if (i < 0) i = map->paint_tile_width + i;
|
||||||
|
if (j < 0) j = map->paint_tile_height + j;
|
||||||
|
int tile = map->getSelectedBlockIndex(map->paint_tile_index + i + (j * 8));
|
||||||
|
uint old_tile = block->tile;
|
||||||
|
if (old_tile == tile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
block->tile = tile;
|
||||||
|
map->_setBlock(x, y, *block);
|
||||||
|
if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x + 1, y));
|
||||||
|
}
|
||||||
|
if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x - 1, y));
|
||||||
|
}
|
||||||
|
if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x, y + 1));
|
||||||
|
}
|
||||||
|
if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x, y - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
|
||||||
|
// Smart path should never be enabled without a 3x3 block selection.
|
||||||
|
if (map->paint_tile_width != 3 || map->paint_tile_height != 3) return;
|
||||||
|
|
||||||
|
// Shift to the middle tile of the smart path selection.
|
||||||
|
int openTile = map->paint_tile_index + 8 + 1;
|
||||||
|
|
||||||
|
// Flood fill the region with the open tile.
|
||||||
|
QList<QPoint> todo;
|
||||||
|
todo.append(QPoint(initialX, initialY));
|
||||||
|
while (todo.length()) {
|
||||||
|
QPoint point = todo.takeAt(0);
|
||||||
|
int x = point.x();
|
||||||
|
int y = point.y();
|
||||||
|
|
||||||
|
Block *block = map->getBlock(x, y);
|
||||||
|
if (block == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tile = map->getSelectedBlockIndex(openTile);
|
||||||
|
uint old_tile = block->tile;
|
||||||
|
if (old_tile == tile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
block->tile = tile;
|
||||||
|
map->_setBlock(x, y, *block);
|
||||||
|
if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x + 1, y));
|
||||||
|
}
|
||||||
|
if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x - 1, y));
|
||||||
|
}
|
||||||
|
if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x, y + 1));
|
||||||
|
}
|
||||||
|
if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
|
||||||
|
todo.append(QPoint(x, y - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go back and resolve the flood-filled edge tiles.
|
||||||
|
// Mark tiles as visited while we go.
|
||||||
|
bool visited[map->getWidth() * map->getHeight()];
|
||||||
|
for (int i = 0; i < sizeof visited; i++)
|
||||||
|
visited[i] = false;
|
||||||
|
|
||||||
|
todo.append(QPoint(initialX, initialY));
|
||||||
|
while (todo.length()) {
|
||||||
|
QPoint point = todo.takeAt(0);
|
||||||
|
int x = point.x();
|
||||||
|
int y = point.y();
|
||||||
|
visited[x + y * map->getWidth()] = true;
|
||||||
|
|
||||||
|
Block *block = map->getBlock(x, y);
|
||||||
|
if (block == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int id = 0;
|
||||||
|
Block *top = map->getBlock(x, y - 1);
|
||||||
|
Block *right = map->getBlock(x + 1, y);
|
||||||
|
Block *bottom = map->getBlock(x, y + 1);
|
||||||
|
Block *left = map->getBlock(x - 1, y);
|
||||||
|
|
||||||
|
// Get marching squares value, to determine which tile to use.
|
||||||
|
if (top && IS_SMART_PATH_TILE(top))
|
||||||
|
id += 1;
|
||||||
|
if (right && IS_SMART_PATH_TILE(right))
|
||||||
|
id += 2;
|
||||||
|
if (bottom && IS_SMART_PATH_TILE(bottom))
|
||||||
|
id += 4;
|
||||||
|
if (left && IS_SMART_PATH_TILE(left))
|
||||||
|
id += 8;
|
||||||
|
|
||||||
|
block->tile = map->getSelectedBlockIndex(map->paint_tile_index + smartPathTable[id]);
|
||||||
|
map->_setBlock(x, y, *block);
|
||||||
|
|
||||||
|
// Visit neighbors if they are smart-path tiles, and don't revisit any.
|
||||||
|
if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && IS_SMART_PATH_TILE(block)) {
|
||||||
|
todo.append(QPoint(x + 1, y));
|
||||||
|
visited[x + 1 + y * map->getWidth()] = true;
|
||||||
|
}
|
||||||
|
if (!visited[x - 1 + y * map->getWidth()] && (block = map->getBlock(x - 1, y)) && IS_SMART_PATH_TILE(block)) {
|
||||||
|
todo.append(QPoint(x - 1, y));
|
||||||
|
visited[x - 1 + y * map->getWidth()] = true;
|
||||||
|
}
|
||||||
|
if (!visited[x + (y + 1) * map->getWidth()] && (block = map->getBlock(x, y + 1)) && IS_SMART_PATH_TILE(block)) {
|
||||||
|
todo.append(QPoint(x, y + 1));
|
||||||
|
visited[x + (y + 1) * map->getWidth()] = true;
|
||||||
|
}
|
||||||
|
if (!visited[x + (y - 1) * map->getWidth()] && (block = map->getBlock(x, y - 1)) && IS_SMART_PATH_TILE(block)) {
|
||||||
|
todo.append(QPoint(x, y - 1));
|
||||||
|
visited[x + (y - 1) * map->getWidth()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
|
void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
|
||||||
QPointF pos = event->pos();
|
QPointF pos = event->pos();
|
||||||
int x = (int)(pos.x()) / 16;
|
int x = (int)(pos.x()) / 16;
|
||||||
|
|
2
editor.h
2
editor.h
|
@ -250,6 +250,8 @@ public:
|
||||||
QList<QPoint> selection;
|
QList<QPoint> selection;
|
||||||
virtual void paint(QGraphicsSceneMouseEvent*);
|
virtual void paint(QGraphicsSceneMouseEvent*);
|
||||||
virtual void floodFill(QGraphicsSceneMouseEvent*);
|
virtual void floodFill(QGraphicsSceneMouseEvent*);
|
||||||
|
void _floodFill(int x, int y);
|
||||||
|
void _floodFillSmartPath(int initialX, int initialY);
|
||||||
virtual void pick(QGraphicsSceneMouseEvent*);
|
virtual void pick(QGraphicsSceneMouseEvent*);
|
||||||
virtual void select(QGraphicsSceneMouseEvent*);
|
virtual void select(QGraphicsSceneMouseEvent*);
|
||||||
virtual void draw(bool ignoreCache = false);
|
virtual void draw(bool ignoreCache = false);
|
||||||
|
|
|
@ -909,3 +909,8 @@ void MainWindow::on_pushButton_clicked()
|
||||||
onMapNeedsRedrawing(editor->map);
|
onMapNeedsRedrawing(editor->map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_checkBox_smartPaths_stateChanged(int selected)
|
||||||
|
{
|
||||||
|
editor->map->smart_paths_enabled = selected == Qt::Checked;
|
||||||
|
}
|
||||||
|
|
|
@ -96,6 +96,8 @@ private slots:
|
||||||
|
|
||||||
void on_pushButton_clicked();
|
void on_pushButton_clicked();
|
||||||
|
|
||||||
|
void on_checkBox_smartPaths_stateChanged(int selected);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
QStandardItemModel *mapListModel;
|
QStandardItemModel *mapListModel;
|
||||||
|
|
|
@ -228,10 +228,20 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="checkBox_ToggleGrid">
|
<widget class="QCheckBox" name="checkBox_smartPaths">
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">margin-left: 10px</string>
|
<string notr="true">margin-left: 10px</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Smart Paths</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_ToggleGrid">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show Grid</string>
|
<string>Show Grid</string>
|
||||||
</property>
|
</property>
|
||||||
|
|
42
map.cpp
42
map.cpp
|
@ -389,7 +389,7 @@ void Map::drawSelection(int i, int w, int selectionWidth, int selectionHeight, Q
|
||||||
int y = i / w;
|
int y = i / w;
|
||||||
painter->save();
|
painter->save();
|
||||||
|
|
||||||
QColor penColor = smart_paths_enabled ? QColor(0xff, 0x0, 0xff) : QColor(0xff, 0xff, 0xff);
|
QColor penColor = QColor(0xff, 0xff, 0xff);
|
||||||
painter->setPen(penColor);
|
painter->setPen(penColor);
|
||||||
int rectWidth = selectionWidth * 16;
|
int rectWidth = selectionWidth * 16;
|
||||||
int rectHeight = selectionHeight * 16;
|
int rectHeight = selectionHeight * 16;
|
||||||
|
@ -477,38 +477,6 @@ void Map::_setBlock(int x, int y, Block block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::_floodFill(int x, int y, uint tile) {
|
|
||||||
QList<QPoint> todo;
|
|
||||||
todo.append(QPoint(x, y));
|
|
||||||
while (todo.length()) {
|
|
||||||
QPoint point = todo.takeAt(0);
|
|
||||||
x = point.x();
|
|
||||||
y = point.y();
|
|
||||||
Block *block = getBlock(x, y);
|
|
||||||
if (block == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
uint old_tile = block->tile;
|
|
||||||
if (old_tile == tile) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
block->tile = tile;
|
|
||||||
_setBlock(x, y, *block);
|
|
||||||
if ((block = getBlock(x + 1, y)) && block->tile == old_tile) {
|
|
||||||
todo.append(QPoint(x + 1, y));
|
|
||||||
}
|
|
||||||
if ((block = getBlock(x - 1, y)) && block->tile == old_tile) {
|
|
||||||
todo.append(QPoint(x - 1, y));
|
|
||||||
}
|
|
||||||
if ((block = getBlock(x, y + 1)) && block->tile == old_tile) {
|
|
||||||
todo.append(QPoint(x, y + 1));
|
|
||||||
}
|
|
||||||
if ((block = getBlock(x, y - 1)) && block->tile == old_tile) {
|
|
||||||
todo.append(QPoint(x, y - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Map::_floodFillCollision(int x, int y, uint collision) {
|
void Map::_floodFillCollision(int x, int y, uint collision) {
|
||||||
QList<QPoint> todo;
|
QList<QPoint> todo;
|
||||||
todo.append(QPoint(x, y));
|
todo.append(QPoint(x, y));
|
||||||
|
@ -666,14 +634,6 @@ void Map::setBlock(int x, int y, Block block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::floodFill(int x, int y, uint tile) {
|
|
||||||
Block *block = getBlock(x, y);
|
|
||||||
if (block && block->tile != tile) {
|
|
||||||
_floodFill(x, y, tile);
|
|
||||||
commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Map::floodFillCollision(int x, int y, uint collision) {
|
void Map::floodFillCollision(int x, int y, uint collision) {
|
||||||
Block *block = getBlock(x, y);
|
Block *block = getBlock(x, y);
|
||||||
if (block && block->collision != collision) {
|
if (block && block->collision != collision) {
|
||||||
|
|
2
map.h
2
map.h
|
@ -184,8 +184,6 @@ public:
|
||||||
void setBlock(int x, int y, Block block);
|
void setBlock(int x, int y, Block block);
|
||||||
void _setBlock(int x, int y, Block block);
|
void _setBlock(int x, int y, Block block);
|
||||||
|
|
||||||
void floodFill(int x, int y, uint tile);
|
|
||||||
void _floodFill(int x, int y, uint tile);
|
|
||||||
void floodFillCollision(int x, int y, uint collision);
|
void floodFillCollision(int x, int y, uint collision);
|
||||||
void _floodFillCollision(int x, int y, uint collision);
|
void _floodFillCollision(int x, int y, uint collision);
|
||||||
void floodFillElevation(int x, int y, uint elevation);
|
void floodFillElevation(int x, int y, uint elevation);
|
||||||
|
|
Loading…
Reference in a new issue