Add new metatile image export window

This commit is contained in:
GriffinR
2025-07-02 14:23:57 -04:00
parent b2798e77d4
commit 38e2772213
35 changed files with 1276 additions and 326 deletions

View File

@@ -54,7 +54,8 @@ protected:
static bool getConfigBool(const QString &key, const QString &value);
static int getConfigInteger(const QString &key, const QString &value, int min = INT_MIN, int max = INT_MAX, int defaultValue = 0);
static uint32_t getConfigUint32(const QString &key, const QString &value, uint32_t min = 0, uint32_t max = UINT_MAX, uint32_t defaultValue = 0);
static QColor getConfigColor(const QString &key, const QString &value, const QColor &defaultValue = Qt::black);
static QColor getConfigColor(const QString &key, const QString &value, const QColor &defaultValue = QColor(Qt::black));
static QString toConfigColor(const QColor &color);
QString m_root;
QString m_filename;
@@ -82,7 +83,7 @@ public:
this->collisionOpacity = 50;
this->collisionZoom = 30;
this->metatilesZoom = 30;
this->tilesetEditorMetatilesZoom = 45;
this->tilesetEditorMetatilesZoom = 30;
this->tilesetEditorTilesZoom = 30;
this->showPlayerView = false;
this->showCursorTile = true;
@@ -351,7 +352,7 @@ public:
this->prefabImportPrompted = false;
this->tilesetsHaveCallback = true;
this->tilesetsHaveIsCompressed = true;
this->setTransparentPixelsBlack = true;
this->transparencyColor = QColor(Qt::black);
this->preserveMatchingOnlyData = false;
this->filePaths.clear();
this->eventIconPaths.clear();
@@ -426,7 +427,7 @@ public:
bool prefabImportPrompted;
bool tilesetsHaveCallback;
bool tilesetsHaveIsCompressed;
bool setTransparentPixelsBlack;
QColor transparencyColor;
bool preserveMatchingOnlyData;
int metatileAttributesSize;
uint32_t metatileBehaviorMask;

View File

@@ -65,14 +65,24 @@ public:
} lastCommitBlocks; // to track map changes
void setMetatileLayerOrder(const QList<int> &layerOrder) { m_metatileLayerOrder = layerOrder; }
QList<int> metatileLayerOrder() const;
static void setDefaultMetatileLayerOrder(const QList<int> &layerOrder) { s_defaultMetatileLayerOrder = layerOrder; }
static QList<int> defaultMetatileLayerOrder();
const QList<int> &metatileLayerOrder() const {
return !m_metatileLayerOrder.isEmpty() ? m_metatileLayerOrder : Layout::globalMetatileLayerOrder();
}
static void setGlobalMetatileLayerOrder(const QList<int> &layerOrder) { s_globalMetatileLayerOrder = layerOrder; }
static const QList<int> &globalMetatileLayerOrder() {
static const QList<int> defaultLayerOrder = {0, 1, 2};
return !s_globalMetatileLayerOrder.isEmpty() ? s_globalMetatileLayerOrder : defaultLayerOrder;
}
void setMetatileLayerOpacity(const QList<float> &layerOpacity) { m_metatileLayerOpacity = layerOpacity; }
QList<float> metatileLayerOpacity() const;
static void setDefaultMetatileLayerOpacity(const QList<float> &layerOpacity) { s_defaultMetatileLayerOpacity = layerOpacity; }
static QList<float> defaultMetatileLayerOpacity();
const QList<float> &metatileLayerOpacity() const {
return !m_metatileLayerOpacity.isEmpty() ? m_metatileLayerOpacity : Layout::globalMetatileLayerOpacity();
}
static void setGlobalMetatileLayerOpacity(const QList<float> &layerOpacity) { s_globalMetatileLayerOpacity = layerOpacity; }
static const QList<float> &globalMetatileLayerOpacity() {
static const QList<float> defaultLayerOpacity = {1.0, 1.0, 1.0};
return !s_globalMetatileLayerOpacity.isEmpty() ? s_globalMetatileLayerOpacity : defaultLayerOpacity;
}
LayoutPixmapItem *layoutItem = nullptr;
CollisionPixmapItem *collisionItem = nullptr;
@@ -166,8 +176,8 @@ private:
QList<int> m_metatileLayerOrder;
QList<float> m_metatileLayerOpacity;
static QList<int> s_defaultMetatileLayerOrder;
static QList<float> s_defaultMetatileLayerOpacity;
static QList<int> s_globalMetatileLayerOrder;
static QList<float> s_globalMetatileLayerOpacity;
signals:
void dimensionsChanged(const QSize &size);

View File

@@ -62,6 +62,14 @@ public:
static void setLayout(Project*);
static QString getMetatileIdString(uint16_t metatileId);
static QString getMetatileIdStrings(const QList<uint16_t> metatileIds);
static QString getLayerName(int layerNum);
static int tileWidth() { return 2; }
static int tileHeight() { return 2; }
static int tilesPerLayer() { return Metatile::tileWidth() * Metatile::tileHeight(); }
static int pixelWidth() { return Metatile::tileWidth() * Tile::pixelWidth(); }
static int pixelHeight() { return Metatile::tileHeight() * Tile::pixelHeight(); }
static QSize pixelSize() { return QSize(pixelWidth(), pixelHeight()); }
inline bool operator==(const Metatile &other) {
return this->tiles == other.tiles && this->attributes == other.attributes;

View File

@@ -3,6 +3,7 @@
#define TILE_H
#include <QObject>
#include <QSize>
class Tile
{
@@ -24,6 +25,10 @@ public:
static int getIndexInTileset(int);
static const uint16_t maxValue;
static int pixelWidth() { return 8; }
static int pixelHeight() { return 8; }
static QSize pixelSize() { return QSize(Tile::pixelWidth(), Tile::pixelHeight()); }
};
inline bool operator==(const Tile &a, const Tile &b) {

View File

@@ -38,6 +38,7 @@ public:
QList<QList<QRgb>> palettes;
QList<QList<QRgb>> palettePreviews;
static QString stripPrefix(const QString &fullName);
static Tileset* getMetatileTileset(int, Tileset*, Tileset*);
static Tileset* getTileTileset(int, Tileset*, Tileset*);
static Metatile* getMetatile(int, Tileset*, Tileset*);

View File

@@ -7,7 +7,7 @@
namespace Util {
void numericalModeSort(QStringList &list);
int roundUp(int numToRound, int multiple);
int roundUpToMultiple(int numToRound, int multiple);
QString toDefineCase(QString input);
QString toHexString(uint32_t value, int minLength = 0);
QString toHtmlParagraph(const QString &text);

View File

@@ -12,8 +12,10 @@ QImage getCollisionMetatileImage(Block);
QImage getCollisionMetatileImage(int, int);
QImage getMetatileImage(uint16_t, Layout*, bool useTruePalettes = false);
QImage getMetatileImage(Metatile*, Layout*, bool useTruePalettes = false);
QImage getMetatileImage(uint16_t, Tileset*, Tileset*, const QList<int>&, const QList<float>&, bool useTruePalettes = false);
QImage getMetatileImage(Metatile*, Tileset*, Tileset*, const QList<int>&, const QList<float>&, bool useTruePalettes = false);
QImage getMetatileImage(uint16_t, Tileset*, Tileset*, const QList<int>&, const QList<float>& = {}, bool useTruePalettes = false);
QImage getMetatileImage(Metatile*, Tileset*, Tileset*, const QList<int>&, const QList<float>& = {}, bool useTruePalettes = false);
QImage getMetatileSheetImage(Layout *, int, bool useTruePalettes = false);
QImage getMetatileSheetImage(Tileset *, Tileset *, uint16_t, int, int, const QList<int> &, const QList<float> & = {}, const QSize &size = Metatile::pixelSize(), 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);

View File

@@ -0,0 +1,101 @@
#ifndef METATILEIMAGEEXPORTER_H
#define METATILEIMAGEEXPORTER_H
#include <QDialog>
#include <QGraphicsScene>
#include <QShowEvent>
#include <QCloseEvent>
#include <QListWidget>
#include <QDropEvent>
#include <QRadioButton>
#include "config.h"
class Tileset;
namespace Ui {
class MetatileImageExporter;
}
class ReorderableListWidget : public QListWidget
{
Q_OBJECT
public:
explicit ReorderableListWidget(QWidget *parent = nullptr) : QListWidget(parent) {
setDragEnabled(true);
setDragDropMode(QAbstractItemView::InternalMove);
setDefaultDropAction(Qt::MoveAction);
};
signals:
void reordered();
protected:
virtual void dropEvent(QDropEvent *event) override {
QListWidget::dropEvent(event);
if (event->isAccepted()) {
emit reordered();
}
}
};
class MetatileImageExporter : public QDialog
{
Q_OBJECT
public:
struct Settings {
OrderedMap<int,bool> layerOrder = {
{2, true},
{1, true},
{0, true},
};
uint16_t metatileStart = 0;
uint16_t metatileEnd = 0xFFFF;
uint16_t numMetatilesWide = 8;
bool usePrimaryTileset = true;
bool useSecondaryTileset = false;
bool renderPlaceholders = false;
int transparencyMode = 0;
};
explicit MetatileImageExporter(QWidget *parent, Tileset *primaryTileset, Tileset *secondaryTileset, Settings *savedSettings = nullptr);
~MetatileImageExporter();
protected:
virtual void showEvent(QShowEvent *) override;
virtual void closeEvent(QCloseEvent *) override;
private:
Ui::MetatileImageExporter *ui;
Tileset *m_primaryTileset;
Tileset *m_secondaryTileset;
Settings *m_savedSettings;
QGraphicsScene *m_scene = nullptr;
QGraphicsPixmapItem *m_preview = nullptr;
bool m_previewUpdateQueued = false;
QList<int> m_layerOrder;
ProjectConfig m_savedConfig;
QList<QRadioButton*> m_transparencyButtons;
void applySettings(const Settings &settings);
void updatePreview();
void tryUpdatePreview();
void queuePreviewUpdate();
void updateTilesetUI();
void syncPixelWidth();
void syncMetatileWidth();
void validateMetatileStart();
void validateMetatileEnd();
uint16_t getExpectedMetatileStart();
uint16_t getExpectedMetatileEnd();
void updateMetatileRange();
void copyRenderSettings();
void restoreRenderSettings();
void saveImage();
void reset();
};
#endif // METATILEIMAGEEXPORTER_H

View File

@@ -8,6 +8,7 @@
#include "tileseteditormetatileselector.h"
#include "tileseteditortileselector.h"
#include "metatilelayersitem.h"
#include "metatileimageexporter.h"
class NoScrollComboBox;
class Layout;
@@ -71,10 +72,6 @@ private slots:
void on_spinBox_paletteSelector_valueChanged(int arg1);
void on_actionImport_Primary_Tiles_triggered();
void on_actionImport_Secondary_Tiles_triggered();
void on_actionChange_Metatiles_Count_triggered();
void on_actionChange_Palettes_triggered();
@@ -91,14 +88,6 @@ private slots:
void on_lineEdit_metatileLabel_editingFinished();
void on_actionExport_Primary_Tiles_Image_triggered();
void on_actionExport_Secondary_Tiles_Image_triggered();
void on_actionExport_Primary_Metatiles_Image_triggered();
void on_actionExport_Secondary_Metatiles_Image_triggered();
void on_actionImport_Primary_Metatiles_triggered();
void on_actionImport_Secondary_Metatiles_triggered();
void on_copyButton_metatileLabel_clicked();
void on_actionCut_triggered();
@@ -122,8 +111,10 @@ private:
void drawSelectedTiles();
void redrawTileSelector();
void redrawMetatileSelector();
void importTilesetTiles(Tileset*, bool);
void importTilesetMetatiles(Tileset*, bool);
void importTilesetTiles(Tileset*);
void importAdvanceMapMetatiles(Tileset*);
void exportTilesImage(Tileset*);
void exportMetatilesImage();
void refresh();
void commitMetatileLabel();
void closeEvent(QCloseEvent*);
@@ -170,6 +161,7 @@ private:
QGraphicsScene *metatileLayersScene = nullptr;
bool lockSelection = false;
QSet<uint16_t> metatileReloadQueue;
MetatileImageExporter::Settings *metatileImageExportSettings = nullptr;
bool save();

View File

@@ -21,8 +21,6 @@ public:
uint16_t getSelectedMetatileId();
void updateSelectedMetatile();
QPoint getMetatileIdCoordsOnWidget(uint16_t metatileId);
QImage buildPrimaryMetatilesImage();
QImage buildSecondaryMetatilesImage();
QVector<uint16_t> usedMetatiles;
bool selectorShowUnused = false;
@@ -56,8 +54,6 @@ private:
void drawFilters();
void drawUnused();
void drawCounts();
QImage buildAllMetatilesImage();
QImage buildImage(int metatileIdStart, int numMetatiles);
int numPrimaryMetatilesRounded() const;
signals:

View File

@@ -21,6 +21,7 @@ public:
uint32_t value() const { return m_value; }
uint32_t minimum() const { return m_minimum; }
uint32_t maximum() const { return m_maximum; }
uint32_t singleStep() const { return m_singleStep; }
QString prefix() const { return m_prefix; }
int displayIntegerBase() const { return m_displayIntegerBase; }
bool hasPadding() const { return m_hasPadding; }
@@ -28,6 +29,7 @@ public:
void setMinimum(uint32_t min);
void setMaximum(uint32_t max);
void setRange(uint32_t min, uint32_t max);
void setSingleStep(uint32_t val);
void setPrefix(const QString &prefix);
void setDisplayIntegerBase(int base);
void setHasPadding(bool enabled);
@@ -36,6 +38,7 @@ private:
uint32_t m_minimum;
uint32_t m_maximum;
uint32_t m_value;
uint32_t m_singleStep;
QString m_prefix;
int m_displayIntegerBase;
bool m_hasPadding;