mirror of
https://github.com/huderlem/porymap.git
synced 2026-03-21 17:45:44 -05:00
Enforce tile/metatile limits on load, fix tile selector performance
This commit is contained in:
parent
70aeda9adb
commit
dc4b1ef93a
|
|
@ -29,6 +29,7 @@ public:
|
|||
static constexpr int pixelWidth() { return 8; }
|
||||
static constexpr int pixelHeight() { return 8; }
|
||||
static constexpr QSize pixelSize() { return QSize(Tile::pixelWidth(), Tile::pixelHeight()); }
|
||||
static constexpr int sizeInBytes() { return sizeof(uint16_t); }
|
||||
};
|
||||
|
||||
inline bool operator==(const Tile &a, const Tile &b) {
|
||||
|
|
|
|||
|
|
@ -30,10 +30,8 @@ public:
|
|||
QString metatile_attrs_label;
|
||||
QString metatile_attrs_path;
|
||||
QString tilesImagePath;
|
||||
QImage tilesImage;
|
||||
QStringList palettePaths;
|
||||
|
||||
QList<QImage> tiles;
|
||||
QHash<int, QString> metatileLabels;
|
||||
QList<QList<QRgb>> palettes;
|
||||
QList<QList<QRgb>> palettePreviews;
|
||||
|
|
@ -77,15 +75,24 @@ public:
|
|||
void setMetatiles(const QList<Metatile*> &metatiles);
|
||||
void addMetatile(Metatile* metatile);
|
||||
|
||||
QList<Metatile*> metatiles() const { return m_metatiles; }
|
||||
const QList<Metatile*> &metatiles() const { return m_metatiles; }
|
||||
Metatile* metatileAt(unsigned int i) const { return m_metatiles.at(i); }
|
||||
|
||||
void clearMetatiles();
|
||||
void resizeMetatiles(int newNumMetatiles);
|
||||
int numMetatiles() const { return m_metatiles.length(); }
|
||||
int maxMetatiles() const;
|
||||
|
||||
int numTiles() const { return m_tiles.length(); }
|
||||
int maxTiles() const;
|
||||
|
||||
QImage tileImage(uint16_t tileId) const { return m_tiles.value(Tile::getIndexInTileset(tileId)); }
|
||||
|
||||
private:
|
||||
QList<Metatile*> m_metatiles;
|
||||
|
||||
QList<QImage> m_tiles;
|
||||
QImage m_tilesImage;
|
||||
bool m_hasUnsavedTilesImage = false;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -255,10 +255,13 @@ public:
|
|||
static QMargins getMetatileViewDistance();
|
||||
static int getNumTilesPrimary() { return num_tiles_primary; }
|
||||
static int getNumTilesTotal() { return num_tiles_total; }
|
||||
static int getNumTilesSecondary() { return getNumTilesTotal() - getNumTilesPrimary(); }
|
||||
static int getNumMetatilesPrimary() { return num_metatiles_primary; }
|
||||
static int getNumMetatilesTotal() { return Block::getMaxMetatileId() + 1; }
|
||||
static int getNumMetatilesSecondary() { return getNumMetatilesTotal() - getNumMetatilesPrimary(); }
|
||||
static int getNumPalettesPrimary(){ return num_pals_primary; }
|
||||
static int getNumPalettesTotal() { return num_pals_total; }
|
||||
static int getNumPalettesSecondary() { return getNumPalettesTotal() - getNumPalettesPrimary(); }
|
||||
static QString getEmptyMapsecName();
|
||||
static QString getMapGroupPrefix();
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ protected:
|
|||
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
|
||||
|
||||
private:
|
||||
QPixmap basePixmap;
|
||||
bool externalSelection;
|
||||
int externalSelectionWidth;
|
||||
int externalSelectionHeight;
|
||||
|
|
@ -63,7 +64,7 @@ private:
|
|||
QList<QRgb> getCurPaletteTable();
|
||||
QList<Tile> buildSelectedTiles(int, int, QList<Tile>);
|
||||
QImage buildImage(int tileIdStart, int numTiles);
|
||||
|
||||
void updateBasePixmap();
|
||||
void drawUnused();
|
||||
|
||||
signals:
|
||||
|
|
|
|||
|
|
@ -20,15 +20,15 @@ Tileset::Tileset(const Tileset &other)
|
|||
metatile_attrs_label(other.metatile_attrs_label),
|
||||
metatile_attrs_path(other.metatile_attrs_path),
|
||||
tilesImagePath(other.tilesImagePath),
|
||||
tilesImage(other.tilesImage.copy()),
|
||||
palettePaths(other.palettePaths),
|
||||
metatileLabels(other.metatileLabels),
|
||||
palettes(other.palettes),
|
||||
palettePreviews(other.palettePreviews),
|
||||
m_tilesImage(other.m_tilesImage.copy()),
|
||||
m_hasUnsavedTilesImage(other.m_hasUnsavedTilesImage)
|
||||
{
|
||||
for (auto tile : other.tiles) {
|
||||
tiles.append(tile.copy());
|
||||
for (auto tile : other.m_tiles) {
|
||||
m_tiles.append(tile.copy());
|
||||
}
|
||||
|
||||
for (auto *metatile : other.m_metatiles) {
|
||||
|
|
@ -46,15 +46,15 @@ Tileset &Tileset::operator=(const Tileset &other) {
|
|||
metatile_attrs_label = other.metatile_attrs_label;
|
||||
metatile_attrs_path = other.metatile_attrs_path;
|
||||
tilesImagePath = other.tilesImagePath;
|
||||
tilesImage = other.tilesImage.copy();
|
||||
m_tilesImage = other.m_tilesImage.copy();
|
||||
palettePaths = other.palettePaths;
|
||||
metatileLabels = other.metatileLabels;
|
||||
palettes = other.palettes;
|
||||
palettePreviews = other.palettePreviews;
|
||||
|
||||
tiles.clear();
|
||||
for (auto tile : other.tiles) {
|
||||
tiles.append(tile.copy());
|
||||
m_tiles.clear();
|
||||
for (auto tile : other.m_tiles) {
|
||||
m_tiles.append(tile.copy());
|
||||
}
|
||||
|
||||
clearMetatiles();
|
||||
|
|
@ -94,6 +94,14 @@ void Tileset::resizeMetatiles(int newNumMetatiles) {
|
|||
}
|
||||
}
|
||||
|
||||
int Tileset::maxMetatiles() const {
|
||||
return this->is_secondary ? Project::getNumMetatilesSecondary() : Project::getNumMetatilesPrimary();
|
||||
}
|
||||
|
||||
int Tileset::maxTiles() const {
|
||||
return this->is_secondary ? Project::getNumTilesSecondary() : Project::getNumTilesPrimary();
|
||||
}
|
||||
|
||||
Tileset* Tileset::getTileTileset(int tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
if (tileId < Project::getNumTilesPrimary()) {
|
||||
return primaryTileset;
|
||||
|
|
@ -407,17 +415,25 @@ QHash<int, QString> Tileset::getHeaderMemberMap(bool usingAsm)
|
|||
bool Tileset::loadMetatiles() {
|
||||
clearMetatiles();
|
||||
|
||||
QFile metatiles_file(this->metatiles_path);
|
||||
if (!metatiles_file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatiles_path).arg(metatiles_file.errorString()));
|
||||
QFile file(this->metatiles_path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatiles_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = metatiles_file.readAll();
|
||||
QByteArray data = file.readAll();
|
||||
int tilesPerMetatile = projectConfig.getNumTilesInMetatile();
|
||||
int bytesPerMetatile = 2 * tilesPerMetatile;
|
||||
int num_metatiles = data.length() / bytesPerMetatile;
|
||||
for (int i = 0; i < num_metatiles; i++) {
|
||||
int bytesPerMetatile = Tile::sizeInBytes() * tilesPerMetatile;
|
||||
int numMetatiles = data.length() / bytesPerMetatile;
|
||||
if (numMetatiles > maxMetatiles()) {
|
||||
logWarn(QString("%1 metatile count %2 exceeds limit of %3. Additional metatiles will be ignored.")
|
||||
.arg(this->name)
|
||||
.arg(numMetatiles)
|
||||
.arg(maxMetatiles()));
|
||||
numMetatiles = maxMetatiles();
|
||||
}
|
||||
|
||||
for (int i = 0; i < numMetatiles; i++) {
|
||||
auto metatile = new Metatile;
|
||||
int index = i * bytesPerMetatile;
|
||||
for (int j = 0; j < tilesPerMetatile; j++) {
|
||||
|
|
@ -431,9 +447,9 @@ bool Tileset::loadMetatiles() {
|
|||
}
|
||||
|
||||
bool Tileset::saveMetatiles() {
|
||||
QFile metatiles_file(this->metatiles_path);
|
||||
if (!metatiles_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatiles_path).arg(metatiles_file.errorString()));
|
||||
QFile file(this->metatiles_path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatiles_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -441,31 +457,40 @@ bool Tileset::saveMetatiles() {
|
|||
int numTiles = projectConfig.getNumTilesInMetatile();
|
||||
for (const auto &metatile : m_metatiles) {
|
||||
for (int i = 0; i < numTiles; i++) {
|
||||
uint16_t tile = metatile->tiles.at(i).rawValue();
|
||||
uint16_t tile = metatile->tiles.value(i).rawValue();
|
||||
data.append(static_cast<char>(tile));
|
||||
data.append(static_cast<char>(tile >> 8));
|
||||
}
|
||||
}
|
||||
metatiles_file.write(data);
|
||||
file.write(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tileset::loadMetatileAttributes() {
|
||||
QFile attrs_file(this->metatile_attrs_path);
|
||||
if (!attrs_file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatile_attrs_path).arg(attrs_file.errorString()));
|
||||
QFile file(this->metatile_attrs_path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatile_attrs_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = attrs_file.readAll();
|
||||
QByteArray data = file.readAll();
|
||||
int attrSize = projectConfig.metatileAttributesSize;
|
||||
int numMetatiles = m_metatiles.length();
|
||||
int numMetatileAttrs = data.length() / attrSize;
|
||||
if (numMetatiles != numMetatileAttrs) {
|
||||
logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(numMetatiles).arg(numMetatileAttrs).arg(this->name));
|
||||
if (numMetatileAttrs > numMetatiles) {
|
||||
logWarn(QString("%1 metatile attributes count %2 exceeds metatile count of %3. Additional attributes will be ignored.")
|
||||
.arg(this->name)
|
||||
.arg(numMetatileAttrs)
|
||||
.arg(numMetatiles));
|
||||
numMetatileAttrs = numMetatiles;
|
||||
} else if (numMetatileAttrs < numMetatiles) {
|
||||
logWarn(QString("%1 metatile attributes count %2 is fewer than the metatile count of %3. Missing attributes will default to 0.")
|
||||
.arg(this->name)
|
||||
.arg(numMetatileAttrs)
|
||||
.arg(numMetatiles));
|
||||
}
|
||||
|
||||
for (int i = 0; i < qMin(numMetatiles, numMetatileAttrs); i++) {
|
||||
for (int i = 0; i < numMetatileAttrs; i++) {
|
||||
uint32_t attributes = 0;
|
||||
for (int j = 0; j < attrSize; j++)
|
||||
attributes |= static_cast<unsigned char>(data.at(i * attrSize + j)) << (8 * j);
|
||||
|
|
@ -475,9 +500,9 @@ bool Tileset::loadMetatileAttributes() {
|
|||
}
|
||||
|
||||
bool Tileset::saveMetatileAttributes() {
|
||||
QFile attrs_file(this->metatile_attrs_path);
|
||||
if (!attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatile_attrs_path).arg(attrs_file.errorString()));
|
||||
QFile file(this->metatile_attrs_path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatile_attrs_path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -487,21 +512,36 @@ bool Tileset::saveMetatileAttributes() {
|
|||
for (int i = 0; i < projectConfig.metatileAttributesSize; i++)
|
||||
data.append(static_cast<char>(attributes >> (8 * i)));
|
||||
}
|
||||
attrs_file.write(data);
|
||||
file.write(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tileset::loadTilesImage(QImage *importedImage) {
|
||||
QImage image;
|
||||
bool imported = false;
|
||||
if (importedImage) {
|
||||
image = *importedImage;
|
||||
m_hasUnsavedTilesImage = true;
|
||||
imported = true;
|
||||
} else if (QFile::exists(this->tilesImagePath)) {
|
||||
// No image provided, load from file path.
|
||||
image = QImage(this->tilesImagePath).convertToFormat(QImage::Format_Indexed8, Qt::ThresholdDither);
|
||||
} else {
|
||||
// Use default image
|
||||
}
|
||||
|
||||
if (image.isNull()) {
|
||||
logWarn(QString("Failed to load tiles image for %1. Using default tiles image.").arg(this->name));
|
||||
image = QImage(Tile::pixelWidth(), Tile::pixelHeight(), QImage::Format_Indexed8);
|
||||
image.fill(0);
|
||||
}
|
||||
|
||||
// Validate image dimensions
|
||||
if (image.width() % Tile::pixelWidth() || image.height() % Tile::pixelHeight()) {
|
||||
logError(QString("%1 tiles image has invalid dimensions %2x%3. Dimensions must be a multiple of %4x%5.")
|
||||
.arg(this->name)
|
||||
.arg(image.width())
|
||||
.arg(image.height())
|
||||
.arg(Tile::pixelWidth())
|
||||
.arg(Tile::pixelHeight()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate image contains 16 colors.
|
||||
|
|
@ -515,15 +555,31 @@ bool Tileset::loadTilesImage(QImage *importedImage) {
|
|||
}
|
||||
image.setColorTable(colorTable);
|
||||
}
|
||||
m_tilesImage = image;
|
||||
|
||||
QList<QImage> tiles;
|
||||
// Cut up the full tiles image into individual tile images.
|
||||
m_tiles.clear();
|
||||
for (int y = 0; y < image.height(); y += Tile::pixelHeight())
|
||||
for (int x = 0; x < image.width(); x += Tile::pixelWidth()) {
|
||||
QImage tile = image.copy(x, y, Tile::pixelWidth(), Tile::pixelHeight());
|
||||
tiles.append(tile);
|
||||
m_tiles.append(image.copy(x, y, Tile::pixelWidth(), Tile::pixelHeight()));
|
||||
}
|
||||
this->tilesImage = image;
|
||||
this->tiles = tiles;
|
||||
|
||||
if (m_tiles.length() > maxTiles()) {
|
||||
logWarn(QString("%1 tile count of %2 exceeds limit of %3. Additional tiles will not be displayed.")
|
||||
.arg(this->name)
|
||||
.arg(m_tiles.length())
|
||||
.arg(maxTiles()));
|
||||
|
||||
// Just resize m_tiles so that numTiles() reports the correct tile count.
|
||||
// We'll leave m_tilesImage alone (it doesn't get displayed, and we don't want to delete the user's image data).
|
||||
m_tiles = m_tiles.mid(0, maxTiles());
|
||||
}
|
||||
|
||||
if (imported) {
|
||||
// Only set this flag once we've successfully loaded the tiles image.
|
||||
m_hasUnsavedTilesImage = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -533,7 +589,7 @@ bool Tileset::saveTilesImage() {
|
|||
if (!m_hasUnsavedTilesImage)
|
||||
return true;
|
||||
|
||||
if (!this->tilesImage.save(this->tilesImagePath, "PNG")) {
|
||||
if (!m_tilesImage.save(this->tilesImagePath, "PNG")) {
|
||||
logError(QString("Failed to save tiles image '%1'").arg(this->tilesImagePath));
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2844,7 +2844,9 @@ void MainWindow::on_actionTileset_Editor_triggered()
|
|||
openSubWindow(this->tilesetEditor);
|
||||
|
||||
MetatileSelection selection = this->editor->metatile_selector_item->getMetatileSelection();
|
||||
this->tilesetEditor->selectMetatile(selection.metatileItems.first().metatileId);
|
||||
if (!selection.metatileItems.isEmpty()) {
|
||||
this->tilesetEditor->selectMetatile(selection.metatileItems.first().metatileId);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::initTilesetEditor() {
|
||||
|
|
|
|||
|
|
@ -2461,6 +2461,7 @@ bool Project::readFieldmapMasks() {
|
|||
projectConfig.blockCollisionMask = blockMask;
|
||||
if (readBlockMask(elevationMaskName, &blockMask))
|
||||
projectConfig.blockElevationMask = blockMask;
|
||||
Block::setLayout();
|
||||
|
||||
// Read RSE metatile attribute masks
|
||||
auto it = defines.find(behaviorMaskName);
|
||||
|
|
@ -3469,7 +3470,6 @@ void Project::applyParsedLimits() {
|
|||
projectConfig.metatileEncounterTypeMask &= maxMask;
|
||||
projectConfig.metatileLayerTypeMask &= maxMask;
|
||||
|
||||
Block::setLayout();
|
||||
Metatile::setLayout(this);
|
||||
|
||||
Project::num_metatiles_primary = qBound(1, Project::num_metatiles_primary, Block::getMaxMetatileId() + 1);
|
||||
|
|
|
|||
|
|
@ -546,13 +546,13 @@ int MainWindow::getNumSecondaryTilesetMetatiles() {
|
|||
int MainWindow::getNumPrimaryTilesetTiles() {
|
||||
if (!this->editor || !this->editor->layout || !this->editor->layout->tileset_primary)
|
||||
return 0;
|
||||
return this->editor->layout->tileset_primary->tiles.length();
|
||||
return this->editor->layout->tileset_primary->numTiles();
|
||||
}
|
||||
|
||||
int MainWindow::getNumSecondaryTilesetTiles() {
|
||||
if (!this->editor || !this->editor->layout || !this->editor->layout->tileset_secondary)
|
||||
return 0;
|
||||
return this->editor->layout->tileset_secondary->tiles.length();
|
||||
return this->editor->layout->tileset_secondary->numTiles();
|
||||
}
|
||||
|
||||
QString MainWindow::getPrimaryTileset() {
|
||||
|
|
@ -797,12 +797,15 @@ void MainWindow::setMetatileTile(int metatileId, int tileIndex, QJSValue tileObj
|
|||
QJSValue MainWindow::getTilePixels(int tileId) {
|
||||
if (tileId < 0 || !this->editor || !this->editor->layout)
|
||||
return QJSValue();
|
||||
|
||||
const int numPixels = Tile::pixelWidth() * Tile::pixelHeight();
|
||||
QImage tileImage = getTileImage(tileId, this->editor->layout->tileset_primary, this->editor->layout->tileset_secondary);
|
||||
if (tileImage.isNull() || tileImage.sizeInBytes() < 64)
|
||||
if (tileImage.isNull() || tileImage.sizeInBytes() < numPixels)
|
||||
return QJSValue();
|
||||
|
||||
const uchar * pixels = tileImage.constBits();
|
||||
QJSValue pixelArray = Scripting::getEngine()->newArray(64);
|
||||
for (int i = 0; i < 64; i++) {
|
||||
QJSValue pixelArray = Scripting::getEngine()->newArray(numPixels);
|
||||
for (int i = 0; i < numPixels; i++) {
|
||||
pixelArray.setProperty(i, pixels[i]);
|
||||
}
|
||||
return pixelArray;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ QImage getCollisionMetatileImage(Block block) {
|
|||
}
|
||||
|
||||
QImage getCollisionMetatileImage(int collision, int elevation) {
|
||||
const QImage * image = Editor::collisionIcons.at(collision).at(elevation);
|
||||
const QImage * image = Editor::collisionIcons.value(collision).value(elevation);
|
||||
return image ? *image : QImage();
|
||||
}
|
||||
|
||||
|
|
@ -158,11 +158,7 @@ QImage getMetatileImage(
|
|||
|
||||
QImage getTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
Tileset *tileset = Tileset::getTileTileset(tileId, primaryTileset, secondaryTileset);
|
||||
int index = Tile::getIndexInTileset(tileId);
|
||||
if (!tileset) {
|
||||
return QImage();
|
||||
}
|
||||
return tileset->tiles.value(index, QImage());
|
||||
return tileset ? tileset->tileImage(tileId) : QImage();
|
||||
}
|
||||
|
||||
QImage getColoredTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset, const QList<QRgb> &palette) {
|
||||
|
|
@ -170,10 +166,10 @@ QImage getColoredTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *se
|
|||
if (tileImage.isNull()) {
|
||||
tileImage = QImage(Tile::pixelWidth(), Tile::pixelHeight(), QImage::Format_RGBA8888);
|
||||
QPainter painter(&tileImage);
|
||||
painter.fillRect(0, 0, tileImage.width(), tileImage.height(), palette.at(0));
|
||||
painter.fillRect(0, 0, tileImage.width(), tileImage.height(), palette.value(0));
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
tileImage.setColor(i, palette.at(i));
|
||||
tileImage.setColor(i, palette.value(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -245,26 +241,26 @@ QImage getMetatileSheetImage(Tileset *primaryTileset,
|
|||
const QSize &metatileSize,
|
||||
bool useTruePalettes)
|
||||
{
|
||||
QImage primaryImage = getMetatileSheetImage(primaryTileset,
|
||||
secondaryTileset,
|
||||
0,
|
||||
primaryTileset ? primaryTileset->numMetatiles()-1 : 0,
|
||||
numMetatilesWide,
|
||||
layerOrder,
|
||||
layerOpacity,
|
||||
metatileSize,
|
||||
useTruePalettes);
|
||||
auto createSheetImage = [=](uint16_t start, Tileset *tileset) {
|
||||
uint16_t end = start;
|
||||
if (tileset) {
|
||||
if (tileset->numMetatiles() == 0)
|
||||
return QImage();
|
||||
end += tileset->numMetatiles() - 1;
|
||||
}
|
||||
return getMetatileSheetImage(primaryTileset,
|
||||
secondaryTileset,
|
||||
start,
|
||||
end,
|
||||
numMetatilesWide,
|
||||
layerOrder,
|
||||
layerOpacity,
|
||||
metatileSize,
|
||||
useTruePalettes);
|
||||
};
|
||||
|
||||
uint16_t secondaryMetatileIdStart = Project::getNumMetatilesPrimary();
|
||||
QImage secondaryImage = getMetatileSheetImage(primaryTileset,
|
||||
secondaryTileset,
|
||||
secondaryMetatileIdStart,
|
||||
secondaryMetatileIdStart + (secondaryTileset ? secondaryTileset->numMetatiles()-1 : 0),
|
||||
numMetatilesWide,
|
||||
layerOrder,
|
||||
layerOpacity,
|
||||
metatileSize,
|
||||
useTruePalettes);
|
||||
QImage primaryImage = createSheetImage(0, primaryTileset);
|
||||
QImage secondaryImage = createSheetImage(Project::getNumMetatilesPrimary(), secondaryTileset);
|
||||
|
||||
QImage image(qMax(primaryImage.width(), secondaryImage.width()), primaryImage.height() + secondaryImage.height(), QImage::Format_RGBA8888);
|
||||
image.fill(getInvalidImageColor());
|
||||
|
|
|
|||
|
|
@ -783,7 +783,10 @@ void TilesetEditor::importTilesetTiles(Tileset *tileset) {
|
|||
image = image.convertToFormat(QImage::Format::Format_Indexed8, colorTable);
|
||||
}
|
||||
|
||||
tileset->loadTilesImage(&image);
|
||||
if (!tileset->loadTilesImage(&image)) {
|
||||
RecentErrorMessage::show(QStringLiteral("Failed to import tiles."), this);
|
||||
return;
|
||||
}
|
||||
this->refresh();
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,53 +12,40 @@ QPoint TilesetEditorTileSelector::getSelectionDimensions() {
|
|||
}
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::draw() {
|
||||
if (!this->primaryTileset || !this->secondaryTileset) {
|
||||
this->setPixmap(QPixmap());
|
||||
void TilesetEditorTileSelector::updateBasePixmap() {
|
||||
if (!this->primaryTileset || !this->secondaryTileset || this->numTilesWide == 0) {
|
||||
this->basePixmap = QPixmap();
|
||||
return;
|
||||
}
|
||||
|
||||
int totalTiles = Project::getNumTilesTotal();
|
||||
int primaryLength = this->primaryTileset->tiles.length();
|
||||
int secondaryLength = this->secondaryTileset->tiles.length();
|
||||
int height = totalTiles / this->numTilesWide;
|
||||
QList<QRgb> palette = Tileset::getPalette(this->paletteId, this->primaryTileset, this->secondaryTileset, true);
|
||||
QImage image(this->numTilesWide * this->cellWidth, height * this->cellHeight, QImage::Format_RGBA8888);
|
||||
|
||||
QPainter painter(&image);
|
||||
for (uint16_t tile = 0; tile < totalTiles; tile++) {
|
||||
QImage tileImage;
|
||||
if (tile < primaryLength) {
|
||||
tileImage = getPalettedTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId, true).scaled(this->cellWidth, this->cellHeight);
|
||||
} else if (tile < Project::getNumTilesPrimary()) {
|
||||
tileImage = QImage(this->cellWidth, this->cellHeight, QImage::Format_RGBA8888);
|
||||
tileImage.fill(palette.at(0));
|
||||
} else if (tile < Project::getNumTilesPrimary() + secondaryLength) {
|
||||
tileImage = getPalettedTileImage(tile, this->primaryTileset, this->secondaryTileset, this->paletteId, true).scaled(this->cellWidth, this->cellHeight);
|
||||
} else {
|
||||
tileImage = QImage(this->cellWidth, this->cellHeight, QImage::Format_RGBA8888);
|
||||
QPainter painter(&tileImage);
|
||||
painter.fillRect(0, 0, this->cellWidth, this->cellHeight, palette.at(0));
|
||||
}
|
||||
|
||||
int y = tile / this->numTilesWide;
|
||||
int x = tile % this->numTilesWide;
|
||||
QPoint origin = QPoint(x * this->cellWidth, y * this->cellHeight);
|
||||
painter.drawImage(origin, tileImage);
|
||||
for (uint16_t tileId = 0; tileId < totalTiles; tileId++) {
|
||||
QImage tileImage = getPalettedTileImage(tileId, this->primaryTileset, this->secondaryTileset, this->paletteId, true)
|
||||
.scaled(this->cellWidth, this->cellHeight);
|
||||
int x = (tileId % this->numTilesWide) * this->cellWidth;
|
||||
int y = (tileId / this->numTilesWide) * this->cellHeight;
|
||||
painter.drawImage(x, y, tileImage);
|
||||
}
|
||||
|
||||
if (this->showDivider) {
|
||||
int row = this->primaryTileset->tiles.length() / this->numTilesWide;
|
||||
if (this->primaryTileset->tiles.length() % this->numTilesWide != 0) {
|
||||
// Round up height for incomplete last row
|
||||
row++;
|
||||
}
|
||||
int row = Util::roundUpToMultiple(Project::getNumTilesPrimary(), this->numTilesWide) / this->numTilesWide;
|
||||
const int y = row * this->cellHeight;
|
||||
painter.setPen(Qt::white);
|
||||
painter.drawLine(0, y, this->numTilesWide * this->cellWidth, y);
|
||||
}
|
||||
|
||||
painter.end();
|
||||
this->setPixmap(QPixmap::fromImage(image));
|
||||
this->basePixmap = QPixmap::fromImage(image);
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::draw() {
|
||||
if (this->basePixmap.isNull())
|
||||
updateBasePixmap();
|
||||
setPixmap(this->basePixmap);
|
||||
|
||||
if (!this->externalSelection || (this->externalSelectionWidth == 1 && this->externalSelectionHeight == 1)) {
|
||||
this->drawSelection();
|
||||
|
|
@ -82,12 +69,14 @@ void TilesetEditorTileSelector::highlight(uint16_t tile) {
|
|||
void TilesetEditorTileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
this->primaryTileset = primaryTileset;
|
||||
this->secondaryTileset = secondaryTileset;
|
||||
this->updateBasePixmap();
|
||||
this->draw();
|
||||
}
|
||||
|
||||
void TilesetEditorTileSelector::setPaletteId(int paletteId) {
|
||||
this->paletteId = paletteId;
|
||||
this->paletteChanged = true;
|
||||
this->updateBasePixmap();
|
||||
this->draw();
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +202,7 @@ void TilesetEditorTileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
|
|||
}
|
||||
|
||||
QPoint TilesetEditorTileSelector::getTileCoords(uint16_t tile) {
|
||||
if (tile >= Project::getNumTilesTotal())
|
||||
if (tile >= Project::getNumTilesTotal() || this->numTilesWide == 0)
|
||||
{
|
||||
// Invalid tile.
|
||||
return QPoint(0, 0);
|
||||
|
|
@ -233,17 +222,20 @@ QImage TilesetEditorTileSelector::buildPrimaryTilesIndexedImage() {
|
|||
if (!this->primaryTileset)
|
||||
return QImage();
|
||||
|
||||
return buildImage(0, this->primaryTileset->tiles.length());
|
||||
return buildImage(0, this->primaryTileset->numTiles());
|
||||
}
|
||||
|
||||
QImage TilesetEditorTileSelector::buildSecondaryTilesIndexedImage() {
|
||||
if (!this->secondaryTileset)
|
||||
return QImage();
|
||||
|
||||
return buildImage(Project::getNumTilesPrimary(), this->secondaryTileset->tiles.length());
|
||||
return buildImage(Project::getNumTilesPrimary(), this->secondaryTileset->numTiles());
|
||||
}
|
||||
|
||||
QImage TilesetEditorTileSelector::buildImage(int tileIdStart, int numTiles) {
|
||||
if (this->numTilesWide == 0)
|
||||
return QImage();
|
||||
|
||||
int height = qCeil(numTiles / static_cast<double>(this->numTilesWide));
|
||||
QImage image(this->numTilesWide * Tile::pixelWidth(), height * Tile::pixelHeight(), QImage::Format_RGBA8888);
|
||||
image.fill(0);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user