Преглед на файлове

Add smart path painting

Marcus Huderle преди 6 години
родител
ревизия
e485f23004
променени са 4 файла, в които са добавени 138 реда и са изтрити 24 реда
  1. 130
    22
      editor.cpp
  2. 4
    1
      editor.h
  3. 3
    1
      map.cpp
  4. 1
    0
      map.h

+ 130
- 22
editor.cpp Целия файл

@@ -296,16 +296,25 @@ void MetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
296 296
     int y = ((int)pos.y()) / 16;
297 297
     map->paint_metatile_initial_x = x;
298 298
     map->paint_metatile_initial_y = y;
299
-    updateSelection(event->pos());
299
+    updateSelection(event->pos(), event->button());
300 300
 }
301 301
 void MetatilesPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
302 302
     updateCurHoveredMetatile(event->pos());
303
-    updateSelection(event->pos());
303
+    Qt::MouseButton button = event->button();
304
+    if (button == Qt::MouseButton::NoButton) {
305
+        Qt::MouseButtons heldButtons = event->buttons();
306
+        if (heldButtons & Qt::RightButton) {
307
+            button = Qt::RightButton;
308
+        } else if (heldButtons & Qt::LeftButton) {
309
+            button = Qt::LeftButton;
310
+        }
311
+    }
312
+    updateSelection(event->pos(), button);
304 313
 }
305 314
 void MetatilesPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
306
-    updateSelection(event->pos());
315
+    updateSelection(event->pos(), event->button());
307 316
 }
308
-void MetatilesPixmapItem::updateSelection(QPointF pos) {
317
+void MetatilesPixmapItem::updateSelection(QPointF pos, Qt::MouseButton button) {
309 318
     int x = ((int)pos.x()) / 16;
310 319
     int y = ((int)pos.y()) / 16;
311 320
     int width = pixmap().width() / 16;
@@ -316,6 +325,9 @@ void MetatilesPixmapItem::updateSelection(QPointF pos) {
316 325
         map->paint_tile = baseTileY * 8 + baseTileX;
317 326
         map->paint_tile_width = abs(map->paint_metatile_initial_x - x) + 1;
318 327
         map->paint_tile_height = abs(map->paint_metatile_initial_y - y) + 1;
328
+        map->smart_paths_enabled = button == Qt::RightButton
329
+                                && map->paint_tile_width == 3
330
+                                && map->paint_tile_height == 3;
319 331
         emit map->paintTileChanged(map);
320 332
     }
321 333
 }
@@ -351,25 +363,13 @@ void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
351 363
         QPointF pos = event->pos();
352 364
         int x = (int)(pos.x()) / 16;
353 365
         int y = (int)(pos.y()) / 16;
354
-        // Snap the selected position to the top-left of the block boundary.
355
-        // This allows painting via dragging the mouse to tile the painted region.
356
-        int xDiff = x - map->paint_tile_initial_x;
357
-        int yDiff = y - map->paint_tile_initial_y;
358
-        if (xDiff < 0 && xDiff % map->paint_tile_width != 0) xDiff -= map->paint_tile_width;
359
-        if (yDiff < 0 && yDiff % map->paint_tile_height != 0) yDiff -= map->paint_tile_height;
360
-
361
-        x = map->paint_tile_initial_x + (xDiff / map->paint_tile_width) * map->paint_tile_width;
362
-        y = map->paint_tile_initial_y + (yDiff / map->paint_tile_height) * map->paint_tile_height;
363
-        for (int i = 0; i < map->paint_tile_width && i + x < map->getWidth(); i++)
364
-        for (int j = 0; j < map->paint_tile_height && j + y < map->getHeight(); j++) {
365
-            int actualX = i + x;
366
-            int actualY = j + y;
367
-            Block *block = map->getBlock(actualX, actualY);
368
-            if (block) {
369
-                block->tile = map->paint_tile + i + (j * 8);
370
-                map->_setBlock(actualX, actualY, *block);
371
-            }
366
+
367
+        if (map->smart_paths_enabled) {
368
+            paintSmartPath(x, y);
369
+        } else {
370
+            paintNormal(x, y);
372 371
         }
372
+
373 373
         if (event->type() == QEvent::GraphicsSceneMouseRelease) {
374 374
             map->commit();
375 375
         }
@@ -377,6 +377,114 @@ void MapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
377 377
     }
378 378
 }
379 379
 
380
+void MapPixmapItem::paintNormal(int x, int y) {
381
+    // Snap the selected position to the top-left of the block boundary.
382
+    // This allows painting via dragging the mouse to tile the painted region.
383
+    int xDiff = x - map->paint_tile_initial_x;
384
+    int yDiff = y - map->paint_tile_initial_y;
385
+    if (xDiff < 0 && xDiff % map->paint_tile_width != 0) xDiff -= map->paint_tile_width;
386
+    if (yDiff < 0 && yDiff % map->paint_tile_height != 0) yDiff -= map->paint_tile_height;
387
+
388
+    x = map->paint_tile_initial_x + (xDiff / map->paint_tile_width) * map->paint_tile_width;
389
+    y = map->paint_tile_initial_y + (yDiff / map->paint_tile_height) * map->paint_tile_height;
390
+    for (int i = 0; i < map->paint_tile_width && i + x < map->getWidth(); i++)
391
+    for (int j = 0; j < map->paint_tile_height && j + y < map->getHeight(); j++) {
392
+        int actualX = i + x;
393
+        int actualY = j + y;
394
+        Block *block = map->getBlock(actualX, actualY);
395
+        if (block) {
396
+            block->tile = map->paint_tile + i + (j * 8);
397
+            map->_setBlock(actualX, actualY, *block);
398
+        }
399
+    }
400
+}
401
+
402
+// These are tile offsets from the top-left tile in the 3x3 smart path selection.
403
+// Each entry is for one possibility from the marching squares value for a tile.
404
+// (Marching Squares: https://en.wikipedia.org/wiki/Marching_squares)
405
+QList<int> MapPixmapItem::smartPathTable = QList<int>({
406
+    8 + 1, // 0000
407
+    8 + 1, // 0001
408
+    8 + 1, // 0010
409
+   16 + 0, // 0011
410
+    8 + 1, // 0100
411
+    8 + 1, // 0101
412
+    0 + 0, // 0110
413
+    8 + 0, // 0111
414
+    8 + 1, // 1000
415
+   16 + 2, // 1001
416
+    8 + 1, // 1010
417
+   16 + 1, // 1011
418
+    0 + 2, // 1100
419
+    8 + 2, // 1101
420
+    0 + 1, // 1110
421
+    8 + 1, // 1111
422
+});
423
+
424
+#define IS_SMART_PATH_TILE(block) ((block->tile >= map->paint_tile && block->tile < map->paint_tile + 3) \
425
+                                || (block->tile >= map->paint_tile + 8 && block->tile < map->paint_tile + 11) \
426
+                                || (block->tile >= map->paint_tile + 16 && block->tile < map->paint_tile + 19))
427
+
428
+void MapPixmapItem::paintSmartPath(int x, int y) {
429
+    // Smart path should never be enabled without a 3x3 block selection.
430
+    if (map->paint_tile_width != 3 || map->paint_tile_height != 3) return;
431
+
432
+    // Shift to the middle tile of the smart path selection.
433
+    int openTile = map->paint_tile + 8 + 1;
434
+
435
+    // Fill the region with the open tile.
436
+    for (int i = -1; i <= 1 && i + x < map->getWidth() && i + x >= 0; i++)
437
+    for (int j = -1; j <= 1 && j + y < map->getHeight() && j + y >= 0; j++) {
438
+        int actualX = i + x;
439
+        int actualY = j + y;
440
+        Block *block = map->getBlock(actualX, actualY);
441
+        if (block) {
442
+            block->tile = openTile;
443
+            map->_setBlock(actualX, actualY, *block);
444
+        }
445
+    }
446
+
447
+    // Go back and resolve the edge tiles
448
+    for (int i = -2; i <= 2 && i + x < map->getWidth() && i + x >= 0; i++)
449
+    for (int j = -2; j <= 2 && j + y < map->getHeight() && j + y >= 0; j++) {
450
+        // Ignore the corners, which can't possible be affected by the smart path.
451
+        if ((i == -2 && j == -2) || (i == 2 && j == -2) ||
452
+            (i == -2 && j ==  2) || (i == 2 && j ==  2))
453
+            continue;
454
+
455
+        // Ignore tiles that aren't part of the smart path set.
456
+        int actualX = i + x;
457
+        int actualY = j + y;
458
+        Block *block = map->getBlock(actualX, actualY);
459
+        if (!block || !IS_SMART_PATH_TILE(block)) {
460
+            continue;
461
+        }
462
+
463
+        int id = 0;
464
+        Block *top = map->getBlock(actualX, actualY - 1);
465
+        Block *right = map->getBlock(actualX + 1, actualY);
466
+        Block *bottom = map->getBlock(actualX, actualY + 1);
467
+        Block *left = map->getBlock(actualX - 1, actualY);
468
+
469
+        // Get marching squares value, to determine which tile to use.
470
+        if (top && IS_SMART_PATH_TILE(top))
471
+            id += 1;
472
+        if (right && IS_SMART_PATH_TILE(right))
473
+            id += 2;
474
+        if (bottom && IS_SMART_PATH_TILE(bottom))
475
+            id += 4;
476
+        if (left && IS_SMART_PATH_TILE(left))
477
+            id += 8;
478
+
479
+        if (block) {
480
+            qDebug() << "tile: " << block->tile << "base: " << map->paint_tile << "id: " << id;
481
+        }
482
+
483
+        block->tile = map->paint_tile + smartPathTable[id];;
484
+        map->_setBlock(actualX, actualY, *block);
485
+    }
486
+}
487
+
380 488
 void MapPixmapItem::floodFill(QGraphicsSceneMouseEvent *event) {
381 489
     if (map) {
382 490
         QPointF pos = event->pos();

+ 4
- 1
editor.h Целия файл

@@ -204,6 +204,9 @@ public:
204 204
 
205 205
 private:
206 206
     void updateCurHoveredTile(QPointF pos);
207
+    void paintNormal(int x, int y);
208
+    void paintSmartPath(int x, int y);
209
+    static QList<int> smartPathTable;
207 210
 
208 211
 signals:
209 212
     void mouseEvent(QGraphicsSceneMouseEvent *, MapPixmapItem *);
@@ -250,7 +253,7 @@ public:
250 253
     Map* map = NULL;
251 254
     virtual void draw();
252 255
 private:
253
-    void updateSelection(QPointF pos);
256
+    void updateSelection(QPointF pos, Qt::MouseButton button);
254 257
 protected:
255 258
     virtual void updateCurHoveredMetatile(QPointF pos);
256 259
 private slots:

+ 3
- 1
map.cpp Целия файл

@@ -453,7 +453,9 @@ void Map::drawSelection(int i, int w, QPainter *painter) {
453 453
     int x = i % w;
454 454
     int y = i / w;
455 455
     painter->save();
456
-    painter->setPen(QColor(0xff, 0xff, 0xff));
456
+
457
+    QColor penColor = smart_paths_enabled ? QColor(0xff, 0x0, 0xff) : QColor(0xff, 0xff, 0xff);
458
+    painter->setPen(penColor);
457 459
     int rectWidth = paint_tile_width * 16;
458 460
     int rectHeight = paint_tile_height * 16;
459 461
     painter->drawRect(x * 16, y * 16, rectWidth - 1, rectHeight -1);

+ 1
- 0
map.h Целия файл

@@ -138,6 +138,7 @@ public:
138 138
     QImage image;
139 139
     QPixmap pixmap;
140 140
     QList<QImage> metatile_images;
141
+    bool smart_paths_enabled = false;
141 142
     int paint_metatile_initial_x;
142 143
     int paint_metatile_initial_y;
143 144
     int paint_tile;