From b5bdac8d36eff6fc75ca409c7787e729532603c4 Mon Sep 17 00:00:00 2001
From: GriffinR <griffin.g.richards@gmail.com>
Date: Wed, 1 Dec 2021 16:06:14 -0500
Subject: [PATCH] Add tile/metatile to image functions to API, more
 tile->tileId/metatileId

---
 include/mainwindow.h         |  3 ++
 include/ui/imageproviders.h  |  1 +
 include/ui/overlay.h         |  1 +
 src/mainwindow_scriptapi.cpp | 55 +++++++++++++++++++++++++++++++++
 src/ui/imageproviders.cpp    | 59 +++++++++++++++++++++---------------
 src/ui/overlay.cpp           |  9 ++++++
 6 files changed, 104 insertions(+), 24 deletions(-)

diff --git a/include/mainwindow.h b/include/mainwindow.h
index f6ed14ab..2d4622d5 100644
--- a/include/mainwindow.h
+++ b/include/mainwindow.h
@@ -76,6 +76,9 @@ public:
     Q_INVOKABLE void addFilledRect(int x, int y, int width, int height, QString color = "#000000", int layer = 0);
     Q_INVOKABLE void addImage(int x, int y, QString filepath, int layer = 0);
     Q_INVOKABLE void createImage(int x, int y, QString filepath, int width = -1, int height = -1, unsigned offset = 0, bool hflip = false, bool vflip = false, bool setTransparency = false, int layer = 0);
+    Q_INVOKABLE void addTileImage(int x, int y, int tileId, bool xflip, bool yflip, int palette, int layer = 0);
+    Q_INVOKABLE void addTilesImage(int x, int y, QJSValue tilesObj, int layer = 0);
+    Q_INVOKABLE void addMetatileImage(int x, int y, int metatileId, int layer = 0);
     void refreshAfterPaletteChange(Tileset *tileset);
     void setTilesetPalette(Tileset *tileset, int paletteIndex, QList<QList<int>> colors);
     Q_INVOKABLE void setPrimaryTilesetPalette(int paletteIndex, QList<QList<int>> colors);
diff --git a/include/ui/imageproviders.h b/include/ui/imageproviders.h
index c90ce995..db04bdb2 100644
--- a/include/ui/imageproviders.h
+++ b/include/ui/imageproviders.h
@@ -9,6 +9,7 @@
 QImage getCollisionMetatileImage(Block);
 QImage getCollisionMetatileImage(int, int);
 QImage getMetatileImage(uint16_t, Tileset*, Tileset*, QList<int>, QList<float>, bool useTruePalettes = false);
+QImage getMetatileImage(Metatile*, Tileset*, Tileset*, QList<int>, QList<float>, bool useTruePalettes = false);
 QImage getTileImage(uint16_t, Tileset*, Tileset*);
 QImage getPalettedTileImage(uint16_t, Tileset*, Tileset*, int, bool useTruePalettes = false);
 QImage getGreyscaleTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset);
diff --git a/include/ui/overlay.h b/include/ui/overlay.h
index 68277b16..04ee7764 100644
--- a/include/ui/overlay.h
+++ b/include/ui/overlay.h
@@ -82,6 +82,7 @@ public:
     void addText(QString text, int x, int y, QString color = "#000000", int fontSize = 12);
     void addRect(int x, int y, int width, int height, QString color = "#000000", bool filled = false);
     bool addImage(int x, int y, QString filepath, int width = -1, int height = -1, unsigned offset = 0, bool hflip = false, bool vflip = false, bool setTransparency = false);
+    bool addImage(int x, int y, QImage image);
 private:
     QList<OverlayItem*> items;
     bool hidden;
diff --git a/src/mainwindow_scriptapi.cpp b/src/mainwindow_scriptapi.cpp
index ef7a169c..933991d7 100644
--- a/src/mainwindow_scriptapi.cpp
+++ b/src/mainwindow_scriptapi.cpp
@@ -3,6 +3,7 @@
 #include "scripting.h"
 #include "editcommands.h"
 #include "config.h"
+#include "imageproviders.h"
 
 QJSValue MainWindow::getBlock(int x, int y) {
     if (!this->editor || !this->editor->map)
@@ -291,6 +292,60 @@ void MainWindow::createImage(int x, int y, QString filepath, int width, int heig
         this->ui->graphicsView_Map->scene()->update();
 }
 
+void MainWindow::addTileImage(int x, int y, int tileId, bool xflip, bool yflip, int palette, int layer) {
+    if (!this->ui || !this->ui->graphicsView_Map || layer == INT_MAX
+     || !this->editor || !this->editor->map || !this->editor->map->layout
+     || !this->editor->map->layout->tileset_primary || !this->editor->map->layout->tileset_secondary)
+        return;
+    QImage image = getPalettedTileImage(tileId,
+                                        this->editor->map->layout->tileset_primary,
+                                        this->editor->map->layout->tileset_secondary,
+                                        palette)
+                                        .mirrored(xflip, yflip);
+    if (this->ui->graphicsView_Map->getOverlay(layer)->addImage(x, y, image))
+        this->ui->graphicsView_Map->scene()->update();
+}
+
+void MainWindow::addTilesImage(int x, int y, QJSValue tilesObj, int layer) {
+    if (!this->ui || !this->ui->graphicsView_Map || layer == INT_MAX
+     || !this->editor || !this->editor->map || !this->editor->map->layout
+     || !this->editor->map->layout->tileset_primary || !this->editor->map->layout->tileset_secondary)
+        return;
+
+    // Create metatile from JS tiles array
+    Metatile metatile;
+    int numTiles = this->getNumTilesInMetatile();
+    int numTileObjs = qMin(tilesObj.property("length").toInt(), numTiles);
+    int i = 0;
+    for (; i < numTileObjs; i++)
+        metatile.tiles.append(Scripting::toTile(tilesObj.property(i)));
+    for (; i < numTiles; i++)
+        metatile.tiles.append(Tile());
+
+    // Create image from metatile
+    QImage image = getMetatileImage(&metatile,
+                                    this->editor->map->layout->tileset_primary,
+                                    this->editor->map->layout->tileset_secondary,
+                                    this->editor->map->metatileLayerOrder,
+                                    this->editor->map->metatileLayerOpacity);
+    if (this->ui->graphicsView_Map->getOverlay(layer)->addImage(x, y, image))
+        this->ui->graphicsView_Map->scene()->update();
+}
+
+void MainWindow::addMetatileImage(int x, int y, int metatileId, int layer) {
+    if (!this->ui || !this->ui->graphicsView_Map || layer == INT_MAX
+     || !this->editor || !this->editor->map || !this->editor->map->layout
+     || !this->editor->map->layout->tileset_primary || !this->editor->map->layout->tileset_secondary)
+        return;
+    QImage image = getMetatileImage(static_cast<uint16_t>(metatileId),
+                                    this->editor->map->layout->tileset_primary,
+                                    this->editor->map->layout->tileset_secondary,
+                                    this->editor->map->metatileLayerOrder,
+                                    this->editor->map->metatileLayerOpacity);
+    if (this->ui->graphicsView_Map->getOverlay(layer)->addImage(x, y, image))
+        this->ui->graphicsView_Map->scene()->update();
+}
+
 void MainWindow::refreshAfterPaletteChange(Tileset *tileset) {
     if (this->tilesetEditor) {
         this->tilesetEditor->updateTilesets(this->editor->map->layout->tileset_primary_label, this->editor->map->layout->tileset_secondary_label);
diff --git a/src/ui/imageproviders.cpp b/src/ui/imageproviders.cpp
index f5a4357a..9d714348 100644
--- a/src/ui/imageproviders.cpp
+++ b/src/ui/imageproviders.cpp
@@ -15,7 +15,25 @@ QImage getCollisionMetatileImage(int collision, int elevation) {
 }
 
 QImage getMetatileImage(
-        uint16_t tile,
+        uint16_t metatileId,
+        Tileset *primaryTileset,
+        Tileset *secondaryTileset,
+        QList<int> layerOrder,
+        QList<float> layerOpacity,
+        bool useTruePalettes)
+{
+    Metatile* metatile = Tileset::getMetatile(metatileId, primaryTileset, secondaryTileset);
+    Tileset* blockTileset = Tileset::getBlockTileset(metatileId, primaryTileset, secondaryTileset);
+    if (!metatile || !blockTileset) {
+        QImage metatile_image(16, 16, QImage::Format_RGBA8888);
+        metatile_image.fill(Qt::magenta);
+        return metatile_image;
+    }
+    return getMetatileImage(metatile, primaryTileset, secondaryTileset, layerOrder, layerOpacity, useTruePalettes);
+}
+
+QImage getMetatileImage(
+        Metatile *metatile,
         Tileset *primaryTileset,
         Tileset *secondaryTileset,
         QList<int> layerOrder,
@@ -23,19 +41,12 @@ QImage getMetatileImage(
         bool useTruePalettes)
 {
     QImage metatile_image(16, 16, QImage::Format_RGBA8888);
-    metatile_image.fill(Qt::black);
-
-    Metatile* metatile = Tileset::getMetatile(tile, primaryTileset, secondaryTileset);
     if (!metatile) {
         metatile_image.fill(Qt::magenta);
         return metatile_image;
     }
+    metatile_image.fill(Qt::black);
 
-    Tileset* blockTileset = Tileset::getBlockTileset(tile, primaryTileset, secondaryTileset);
-    if (!blockTileset) {
-        metatile_image.fill(Qt::magenta);
-        return metatile_image;
-    }
     QList<QList<QRgb>> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset, useTruePalettes);
 
     QPainter metatile_painter(&metatile_image);
@@ -46,8 +57,8 @@ QImage getMetatileImage(
     for (int x = 0; x < 2; x++) {
         int l = layerOrder.size() >= numLayers ? layerOrder[layer] : layer;
         int bottomLayer = layerOrder.size() >= numLayers ? layerOrder[0] : 0;
-        Tile tile_ = metatile->tiles.value((y * 2) + x + (l * 4));
-        QImage tile_image = getTileImage(tile_.tileId, primaryTileset, secondaryTileset);
+        Tile tile = metatile->tiles.value((y * 2) + x + (l * 4));
+        QImage tile_image = getTileImage(tile.tileId, primaryTileset, secondaryTileset);
         if (tile_image.isNull()) {
             // Some metatiles specify tiles that are outside the valid range.
             // These are treated as completely transparent, so they can be skipped without
@@ -60,13 +71,13 @@ QImage getMetatileImage(
         }
 
         // Colorize the metatile tiles with its palette.
-        if (tile_.palette < palettes.length()) {
-            QList<QRgb> palette = palettes.value(tile_.palette);
+        if (tile.palette < palettes.length()) {
+            QList<QRgb> palette = palettes.value(tile.palette);
             for (int j = 0; j < palette.length(); j++) {
                 tile_image.setColor(j, palette.value(j));
             }
         } else {
-            logWarn(QString("Tile '%1' is referring to invalid palette number: '%2'").arg(tile_.tileId).arg(tile_.palette));
+            logWarn(QString("Tile '%1' is referring to invalid palette number: '%2'").arg(tile.tileId).arg(tile.palette));
         }
 
         QPoint origin = QPoint(x*8, y*8);
@@ -87,24 +98,24 @@ QImage getMetatileImage(
             tile_image.setColor(0, color.rgba());
         }
 
-        metatile_painter.drawImage(origin, tile_image.mirrored(tile_.xflip, tile_.yflip));
+        metatile_painter.drawImage(origin, tile_image.mirrored(tile.xflip, tile.yflip));
     }
     metatile_painter.end();
 
     return metatile_image;
 }
 
-QImage getTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset) {
-    Tileset *tileset = Tileset::getBlockTileset(tile, primaryTileset, secondaryTileset);
-    int local_index = Metatile::getBlockIndex(tile);
+QImage getTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
+    Tileset *tileset = Tileset::getBlockTileset(tileId, primaryTileset, secondaryTileset);
+    int local_index = Metatile::getBlockIndex(tileId);
     if (!tileset) {
         return QImage();
     }
     return tileset->tiles.value(local_index, QImage());
 }
 
-QImage getColoredTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset, QList<QRgb> palette) {
-    QImage tileImage = getTileImage(tile, primaryTileset, secondaryTileset);
+QImage getColoredTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset, QList<QRgb> palette) {
+    QImage tileImage = getTileImage(tileId, primaryTileset, secondaryTileset);
     if (tileImage.isNull()) {
         tileImage = QImage(16, 16, QImage::Format_RGBA8888);
         QPainter painter(&tileImage);
@@ -118,11 +129,11 @@ QImage getColoredTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *seco
     return tileImage;
 }
 
-QImage getPalettedTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset, int paletteId, bool useTruePalettes) {
+QImage getPalettedTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset, int paletteId, bool useTruePalettes) {
     QList<QRgb> palette = Tileset::getPalette(paletteId, primaryTileset, secondaryTileset, useTruePalettes);
-    return getColoredTileImage(tile, primaryTileset, secondaryTileset, palette);
+    return getColoredTileImage(tileId, primaryTileset, secondaryTileset, palette);
 }
 
-QImage getGreyscaleTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset) {
-    return getColoredTileImage(tile, primaryTileset, secondaryTileset, greyscalePalette);
+QImage getGreyscaleTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
+    return getColoredTileImage(tileId, primaryTileset, secondaryTileset, greyscalePalette);
 }
diff --git a/src/ui/overlay.cpp b/src/ui/overlay.cpp
index 7c7aeab3..058624a8 100644
--- a/src/ui/overlay.cpp
+++ b/src/ui/overlay.cpp
@@ -89,3 +89,12 @@ bool Overlay::addImage(int x, int y, QString filepath, int width, int height, un
     this->items.append(new OverlayImage(x, y, image));
     return true;
 }
+
+bool Overlay::addImage(int x, int y, QImage image) {
+    if (image.isNull()) {
+        logError(QString("Failed to load custom image"));
+        return false;
+    }
+    this->items.append(new OverlayImage(x, y, image));
+    return true;
+}