Browse Source

Make flood fill respect whole metatile selection, including smart path. Smart path is now a checkbox

Marcus Huderle 5 years ago
parent
commit
64095821af
7 changed files with 175 additions and 49 deletions
  1. 154
    5
      editor.cpp
  2. 2
    0
      editor.h
  3. 5
    0
      mainwindow.cpp
  4. 2
    0
      mainwindow.h
  5. 11
    1
      mainwindow.ui
  6. 1
    41
      map.cpp
  7. 0
    2
      map.h

+ 154
- 5
editor.cpp View File

@@ -882,9 +882,6 @@ void MetatilesPixmapItem::updateSelection(QPointF pos, Qt::MouseButton button) {
882 882
         map->paint_tile_index = baseTileY * 8 + baseTileX;
883 883
         map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
884 884
         map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1;
885
-        map->smart_paths_enabled = button == Qt::RightButton
886
-                                && map->paint_tile_width == 3
887
-                                && map->paint_tile_height == 3;
888 885
         emit map->paintTileChanged(map);
889 886
     }
890 887
 }
@@ -1032,7 +1029,7 @@ void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
1032 1029
         int x = (int)(pos.x()) / 16;
1033 1030
         int y = (int)(pos.y()) / 16;
1034 1031
 
1035
-        if (map->smart_paths_enabled) {
1032
+        if (map->smart_paths_enabled && map->paint_tile_width == 3 && map->paint_tile_height == 3) {
1036 1033
             paintSmartPath(x, y);
1037 1034
         } else {
1038 1035
             paintNormal(x, y);
@@ -1160,11 +1157,163 @@ void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
1160 1157
         QPointF pos = event->pos();
1161 1158
         int x = (int)(pos.x()) / 16;
1162 1159
         int y = (int)(pos.y()) / 16;
1163
-        map->floodFill(x, y, map->getSelectedBlockIndex(map->paint_tile_index));
1160
+        Block *block = map->getBlock(x, y);
1161
+        int tile = map->getSelectedBlockIndex(map->paint_tile_index);
1162
+        if (block && block->tile != tile) {
1163
+            if (map->smart_paths_enabled && map->paint_tile_width == 3 && map->paint_tile_height == 3)
1164
+                this->_floodFillSmartPath(x, y);
1165
+            else
1166
+                this->_floodFill(x, y);
1167
+        }
1168
+
1169
+        if (event->type() == QEvent::GraphicsSceneMouseRelease) {
1170
+            map->commit();
1171
+        }
1164 1172
         draw();
1165 1173
     }
1166 1174
 }
1167 1175
 
1176
+void MapPixmapItem::_floodFill(int initialX, int initialY) {
1177
+    QList<QPoint> todo;
1178
+    todo.append(QPoint(initialX, initialY));
1179
+    while (todo.length()) {
1180
+        QPoint point = todo.takeAt(0);
1181
+        int x = point.x();
1182
+        int y = point.y();
1183
+
1184
+        Block *block = map->getBlock(x, y);
1185
+        if (block == NULL) {
1186
+            continue;
1187
+        }
1188
+
1189
+        int xDiff = x - initialX;
1190
+        int yDiff = y - initialY;
1191
+        int i = xDiff % map->paint_tile_width;
1192
+        int j = yDiff % map->paint_tile_height;
1193
+        if (i < 0) i = map->paint_tile_width + i;
1194
+        if (j < 0) j = map->paint_tile_height + j;
1195
+        int tile = map->getSelectedBlockIndex(map->paint_tile_index + i + (j * 8));
1196
+        uint old_tile = block->tile;
1197
+        if (old_tile == tile) {
1198
+            continue;
1199
+        }
1200
+
1201
+        block->tile = tile;
1202
+        map->_setBlock(x, y, *block);
1203
+        if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
1204
+            todo.append(QPoint(x + 1, y));
1205
+        }
1206
+        if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
1207
+            todo.append(QPoint(x - 1, y));
1208
+        }
1209
+        if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
1210
+            todo.append(QPoint(x, y + 1));
1211
+        }
1212
+        if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
1213
+            todo.append(QPoint(x, y - 1));
1214
+        }
1215
+    }
1216
+}
1217
+
1218
+void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
1219
+    // Smart path should never be enabled without a 3x3 block selection.
1220
+    if (map->paint_tile_width != 3 || map->paint_tile_height != 3) return;
1221
+
1222
+    // Shift to the middle tile of the smart path selection.
1223
+    int openTile = map->paint_tile_index + 8 + 1;
1224
+
1225
+    // Flood fill the region with the open tile.
1226
+    QList<QPoint> todo;
1227
+    todo.append(QPoint(initialX, initialY));
1228
+    while (todo.length()) {
1229
+        QPoint point = todo.takeAt(0);
1230
+        int x = point.x();
1231
+        int y = point.y();
1232
+
1233
+        Block *block = map->getBlock(x, y);
1234
+        if (block == NULL) {
1235
+            continue;
1236
+        }
1237
+
1238
+        int tile = map->getSelectedBlockIndex(openTile);
1239
+        uint old_tile = block->tile;
1240
+        if (old_tile == tile) {
1241
+            continue;
1242
+        }
1243
+
1244
+        block->tile = tile;
1245
+        map->_setBlock(x, y, *block);
1246
+        if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
1247
+            todo.append(QPoint(x + 1, y));
1248
+        }
1249
+        if ((block = map->getBlock(x - 1, y)) && block->tile == old_tile) {
1250
+            todo.append(QPoint(x - 1, y));
1251
+        }
1252
+        if ((block = map->getBlock(x, y + 1)) && block->tile == old_tile) {
1253
+            todo.append(QPoint(x, y + 1));
1254
+        }
1255
+        if ((block = map->getBlock(x, y - 1)) && block->tile == old_tile) {
1256
+            todo.append(QPoint(x, y - 1));
1257
+        }
1258
+    }
1259
+
1260
+    // Go back and resolve the flood-filled edge tiles.
1261
+    // Mark tiles as visited while we go.
1262
+    bool visited[map->getWidth() * map->getHeight()];
1263
+    for (int i = 0; i < sizeof visited; i++)
1264
+        visited[i] = false;
1265
+
1266
+    todo.append(QPoint(initialX, initialY));
1267
+    while (todo.length()) {
1268
+        QPoint point = todo.takeAt(0);
1269
+        int x = point.x();
1270
+        int y = point.y();
1271
+        visited[x + y * map->getWidth()] = true;
1272
+
1273
+        Block *block = map->getBlock(x, y);
1274
+        if (block == NULL) {
1275
+            continue;
1276
+        }
1277
+
1278
+        int id = 0;
1279
+        Block *top = map->getBlock(x, y - 1);
1280
+        Block *right = map->getBlock(x + 1, y);
1281
+        Block *bottom = map->getBlock(x, y + 1);
1282
+        Block *left = map->getBlock(x - 1, y);
1283
+
1284
+        // Get marching squares value, to determine which tile to use.
1285
+        if (top && IS_SMART_PATH_TILE(top))
1286
+            id += 1;
1287
+        if (right && IS_SMART_PATH_TILE(right))
1288
+            id += 2;
1289
+        if (bottom && IS_SMART_PATH_TILE(bottom))
1290
+            id += 4;
1291
+        if (left && IS_SMART_PATH_TILE(left))
1292
+            id += 8;
1293
+
1294
+        block->tile = map->getSelectedBlockIndex(map->paint_tile_index + smartPathTable[id]);
1295
+        map->_setBlock(x, y, *block);
1296
+
1297
+        // Visit neighbors if they are smart-path tiles, and don't revisit any.
1298
+        if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && IS_SMART_PATH_TILE(block)) {
1299
+            todo.append(QPoint(x + 1, y));
1300
+            visited[x + 1 + y * map->getWidth()] = true;
1301
+        }
1302
+        if (!visited[x - 1 + y * map->getWidth()] && (block = map->getBlock(x - 1, y)) && IS_SMART_PATH_TILE(block)) {
1303
+            todo.append(QPoint(x - 1, y));
1304
+            visited[x - 1 + y * map->getWidth()] = true;
1305
+        }
1306
+        if (!visited[x + (y + 1) * map->getWidth()] && (block = map->getBlock(x, y + 1)) && IS_SMART_PATH_TILE(block)) {
1307
+            todo.append(QPoint(x, y + 1));
1308
+            visited[x + (y + 1) * map->getWidth()] = true;
1309
+        }
1310
+        if (!visited[x + (y - 1) * map->getWidth()] && (block = map->getBlock(x, y - 1)) && IS_SMART_PATH_TILE(block)) {
1311
+            todo.append(QPoint(x, y - 1));
1312
+            visited[x + (y - 1) * map->getWidth()] = true;
1313
+        }
1314
+    }
1315
+}
1316
+
1168 1317
 void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
1169 1318
     QPointF pos = event->pos();
1170 1319
     int x = (int)(pos.x()) / 16;

+ 2
- 0
editor.h View File

@@ -250,6 +250,8 @@ public:
250 250
     QList<QPoint> selection;
251 251
     virtual void paint(QGraphicsSceneMouseEvent*);
252 252
     virtual void floodFill(QGraphicsSceneMouseEvent*);
253
+    void _floodFill(int x, int y);
254
+    void _floodFillSmartPath(int initialX, int initialY);
253 255
     virtual void pick(QGraphicsSceneMouseEvent*);
254 256
     virtual void select(QGraphicsSceneMouseEvent*);
255 257
     virtual void draw(bool ignoreCache = false);

+ 5
- 0
mainwindow.cpp View File

@@ -909,3 +909,8 @@ void MainWindow::on_pushButton_clicked()
909 909
         onMapNeedsRedrawing(editor->map);
910 910
     }
911 911
 }
912
+
913
+void MainWindow::on_checkBox_smartPaths_stateChanged(int selected)
914
+{
915
+    editor->map->smart_paths_enabled = selected == Qt::Checked;
916
+}

+ 2
- 0
mainwindow.h View File

@@ -96,6 +96,8 @@ private slots:
96 96
 
97 97
     void on_pushButton_clicked();
98 98
 
99
+    void on_checkBox_smartPaths_stateChanged(int selected);
100
+
99 101
 private:
100 102
     Ui::MainWindow *ui;
101 103
     QStandardItemModel *mapListModel;

+ 11
- 1
mainwindow.ui View File

@@ -228,11 +228,21 @@
228 228
                  </widget>
229 229
                 </item>
230 230
                 <item>
231
-                 <widget class="QCheckBox" name="checkBox_ToggleGrid">
231
+                 <widget class="QCheckBox" name="checkBox_smartPaths">
232 232
                   <property name="styleSheet">
233 233
                    <string notr="true">margin-left: 10px</string>
234 234
                   </property>
235 235
                   <property name="text">
236
+                   <string>Smart Paths</string>
237
+                  </property>
238
+                 </widget>
239
+                </item>
240
+                <item>
241
+                 <widget class="QCheckBox" name="checkBox_ToggleGrid">
242
+                  <property name="styleSheet">
243
+                   <string notr="true"/>
244
+                  </property>
245
+                  <property name="text">
236 246
                    <string>Show Grid</string>
237 247
                   </property>
238 248
                  </widget>

+ 1
- 41
map.cpp View File

@@ -389,7 +389,7 @@ void Map::drawSelection(int i, int w, int selectionWidth, int selectionHeight, Q
389 389
     int y = i / w;
390 390
     painter->save();
391 391
 
392
-    QColor penColor = smart_paths_enabled ? QColor(0xff, 0x0, 0xff) : QColor(0xff, 0xff, 0xff);
392
+    QColor penColor = QColor(0xff, 0xff, 0xff);
393 393
     painter->setPen(penColor);
394 394
     int rectWidth = selectionWidth * 16;
395 395
     int rectHeight = selectionHeight * 16;
@@ -477,38 +477,6 @@ void Map::_setBlock(int x, int y, Block block) {
477 477
     }
478 478
 }
479 479
 
480
-void Map::_floodFill(int x, int y, uint tile) {
481
-    QList<QPoint> todo;
482
-    todo.append(QPoint(x, y));
483
-    while (todo.length()) {
484
-            QPoint point = todo.takeAt(0);
485
-            x = point.x();
486
-            y = point.y();
487
-            Block *block = getBlock(x, y);
488
-            if (block == NULL) {
489
-                continue;
490
-            }
491
-            uint old_tile = block->tile;
492
-            if (old_tile == tile) {
493
-                continue;
494
-            }
495
-            block->tile = tile;
496
-            _setBlock(x, y, *block);
497
-            if ((block = getBlock(x + 1, y)) && block->tile == old_tile) {
498
-                todo.append(QPoint(x + 1, y));
499
-            }
500
-            if ((block = getBlock(x - 1, y)) && block->tile == old_tile) {
501
-                todo.append(QPoint(x - 1, y));
502
-            }
503
-            if ((block = getBlock(x, y + 1)) && block->tile == old_tile) {
504
-                todo.append(QPoint(x, y + 1));
505
-            }
506
-            if ((block = getBlock(x, y - 1)) && block->tile == old_tile) {
507
-                todo.append(QPoint(x, y - 1));
508
-            }
509
-    }
510
-}
511
-
512 480
 void Map::_floodFillCollision(int x, int y, uint collision) {
513 481
     QList<QPoint> todo;
514 482
     todo.append(QPoint(x, y));
@@ -666,14 +634,6 @@ void Map::setBlock(int x, int y, Block block) {
666 634
     }
667 635
 }
668 636
 
669
-void Map::floodFill(int x, int y, uint tile) {
670
-    Block *block = getBlock(x, y);
671
-    if (block && block->tile != tile) {
672
-        _floodFill(x, y, tile);
673
-        commit();
674
-    }
675
-}
676
-
677 637
 void Map::floodFillCollision(int x, int y, uint collision) {
678 638
     Block *block = getBlock(x, y);
679 639
     if (block && block->collision != collision) {

+ 0
- 2
map.h View File

@@ -184,8 +184,6 @@ public:
184 184
     void setBlock(int x, int y, Block block);
185 185
     void _setBlock(int x, int y, Block block);
186 186
 
187
-    void floodFill(int x, int y, uint tile);
188
-    void _floodFill(int x, int y, uint tile);
189 187
     void floodFillCollision(int x, int y, uint collision);
190 188
     void _floodFillCollision(int x, int y, uint collision);
191 189
     void floodFillElevation(int x, int y, uint elevation);