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
         map->paint_tile_index = baseTileY * 8 + baseTileX;
882
         map->paint_tile_index = baseTileY * 8 + baseTileX;
883
         map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
883
         map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
884
         map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1;
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
         emit map->paintTileChanged(map);
885
         emit map->paintTileChanged(map);
889
     }
886
     }
890
 }
887
 }
1032
         int x = (int)(pos.x()) / 16;
1029
         int x = (int)(pos.x()) / 16;
1033
         int y = (int)(pos.y()) / 16;
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
             paintSmartPath(x, y);
1033
             paintSmartPath(x, y);
1037
         } else {
1034
         } else {
1038
             paintNormal(x, y);
1035
             paintNormal(x, y);
1160
         QPointF pos = event->pos();
1157
         QPointF pos = event->pos();
1161
         int x = (int)(pos.x()) / 16;
1158
         int x = (int)(pos.x()) / 16;
1162
         int y = (int)(pos.y()) / 16;
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
         draw();
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
 void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
1317
 void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
1169
     QPointF pos = event->pos();
1318
     QPointF pos = event->pos();
1170
     int x = (int)(pos.x()) / 16;
1319
     int x = (int)(pos.x()) / 16;

+ 2
- 0
editor.h View File

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

+ 5
- 0
mainwindow.cpp View File

909
         onMapNeedsRedrawing(editor->map);
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
 
96
 
97
     void on_pushButton_clicked();
97
     void on_pushButton_clicked();
98
 
98
 
99
+    void on_checkBox_smartPaths_stateChanged(int selected);
100
+
99
 private:
101
 private:
100
     Ui::MainWindow *ui;
102
     Ui::MainWindow *ui;
101
     QStandardItemModel *mapListModel;
103
     QStandardItemModel *mapListModel;

+ 11
- 1
mainwindow.ui View File

228
                  </widget>
228
                  </widget>
229
                 </item>
229
                 </item>
230
                 <item>
230
                 <item>
231
-                 <widget class="QCheckBox" name="checkBox_ToggleGrid">
231
+                 <widget class="QCheckBox" name="checkBox_smartPaths">
232
                   <property name="styleSheet">
232
                   <property name="styleSheet">
233
                    <string notr="true">margin-left: 10px</string>
233
                    <string notr="true">margin-left: 10px</string>
234
                   </property>
234
                   </property>
235
                   <property name="text">
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
                    <string>Show Grid</string>
246
                    <string>Show Grid</string>
237
                   </property>
247
                   </property>
238
                  </widget>
248
                  </widget>

+ 1
- 41
map.cpp View File

389
     int y = i / w;
389
     int y = i / w;
390
     painter->save();
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
     painter->setPen(penColor);
393
     painter->setPen(penColor);
394
     int rectWidth = selectionWidth * 16;
394
     int rectWidth = selectionWidth * 16;
395
     int rectHeight = selectionHeight * 16;
395
     int rectHeight = selectionHeight * 16;
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
 void Map::_floodFillCollision(int x, int y, uint collision) {
480
 void Map::_floodFillCollision(int x, int y, uint collision) {
513
     QList<QPoint> todo;
481
     QList<QPoint> todo;
514
     todo.append(QPoint(x, y));
482
     todo.append(QPoint(x, y));
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
 void Map::floodFillCollision(int x, int y, uint collision) {
637
 void Map::floodFillCollision(int x, int y, uint collision) {
678
     Block *block = getBlock(x, y);
638
     Block *block = getBlock(x, y);
679
     if (block && block->collision != collision) {
639
     if (block && block->collision != collision) {

+ 0
- 2
map.h View File

184
     void setBlock(int x, int y, Block block);
184
     void setBlock(int x, int y, Block block);
185
     void _setBlock(int x, int y, Block block);
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
     void floodFillCollision(int x, int y, uint collision);
187
     void floodFillCollision(int x, int y, uint collision);
190
     void _floodFillCollision(int x, int y, uint collision);
188
     void _floodFillCollision(int x, int y, uint collision);
191
     void floodFillElevation(int x, int y, uint elevation);
189
     void floodFillElevation(int x, int y, uint elevation);