Skip to content

Commit

Permalink
Merge pull request #625 from GriffinRichards/metatile-leak
Browse files Browse the repository at this point in the history
Stop leaking tileset metatiles
  • Loading branch information
GriffinRichards authored Oct 20, 2024
2 parents 3b6d3be + 70807fb commit b05f1d9
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 69 deletions.
15 changes: 14 additions & 1 deletion include/core/tileset.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Tileset
Tileset() = default;
Tileset(const Tileset &other);
Tileset &operator=(const Tileset &other);
~Tileset();

public:
QString name;
Expand All @@ -33,7 +34,6 @@ class Tileset
QStringList palettePaths;

QList<QImage> tiles;
QList<Metatile*> metatiles;
QHash<int, QString> metatileLabels;
QList<QList<QRgb>> palettes;
QList<QList<QRgb>> palettePreviews;
Expand All @@ -59,6 +59,19 @@ class Tileset
bool appendToHeaders(QString root, QString friendlyName, bool usingAsm);
bool appendToGraphics(QString root, QString friendlyName, bool usingAsm);
bool appendToMetatiles(QString root, QString friendlyName, bool usingAsm);

void setMetatiles(const QList<Metatile*> &metatiles);
void addMetatile(Metatile* metatile);

QList<Metatile*> metatiles() const { return m_metatiles; }
Metatile* metatileAt(unsigned int i) const { return m_metatiles.at(i); }

void clearMetatiles();
void resizeMetatiles(unsigned int newNumMetatiles);
int numMetatiles() const { return m_metatiles.length(); }

private:
QList<Metatile*> m_metatiles;
};

#endif // TILESET_H
44 changes: 36 additions & 8 deletions src/core/tileset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ Tileset::Tileset(const Tileset &other)
tiles.append(tile.copy());
}

for (auto *metatile : other.metatiles) {
metatiles.append(new Metatile(*metatile));
for (auto *metatile : other.m_metatiles) {
m_metatiles.append(new Metatile(*metatile));
}
}

Expand All @@ -55,14 +55,42 @@ Tileset &Tileset::operator=(const Tileset &other) {
tiles.append(tile.copy());
}

metatiles.clear();
for (auto *metatile : other.metatiles) {
metatiles.append(new Metatile(*metatile));
clearMetatiles();
for (auto *metatile : other.m_metatiles) {
m_metatiles.append(new Metatile(*metatile));
}

return *this;
}

Tileset::~Tileset() {
clearMetatiles();
}

void Tileset::clearMetatiles() {
qDeleteAll(m_metatiles);
m_metatiles.clear();
}

void Tileset::setMetatiles(const QList<Metatile*> &metatiles) {
clearMetatiles();
m_metatiles = metatiles;
}

void Tileset::addMetatile(Metatile* metatile) {
m_metatiles.append(metatile);
}

void Tileset::resizeMetatiles(unsigned int newNumMetatiles) {
while (m_metatiles.length() > newNumMetatiles) {
delete m_metatiles.takeLast();
}
const int numTiles = projectConfig.getNumTilesInMetatile();
while (m_metatiles.length() < newNumMetatiles) {
m_metatiles.append(new Metatile(numTiles));
}
}

Tileset* Tileset::getTileTileset(int tileId, Tileset *primaryTileset, Tileset *secondaryTileset) {
if (tileId < Project::getNumTilesPrimary()) {
return primaryTileset;
Expand All @@ -89,7 +117,7 @@ Metatile* Tileset::getMetatile(int metatileId, Tileset *primaryTileset, Tileset
return nullptr;
}
int index = Metatile::getIndexInTileset(metatileId);
return tileset->metatiles.value(index, nullptr);
return tileset->m_metatiles.value(index, nullptr);
}

// Metatile labels are stored per-tileset. When looking for a metatile label, first search in the tileset
Expand Down Expand Up @@ -178,10 +206,10 @@ bool Tileset::metatileIsValid(uint16_t metatileId, Tileset *primaryTileset, Tile
if (metatileId >= Project::getNumMetatilesTotal())
return false;

if (metatileId < Project::getNumMetatilesPrimary() && metatileId >= primaryTileset->metatiles.length())
if (metatileId < Project::getNumMetatilesPrimary() && metatileId >= primaryTileset->numMetatiles())
return false;

if (metatileId >= Project::getNumMetatilesPrimary() + secondaryTileset->metatiles.length())
if (metatileId >= Project::getNumMetatilesPrimary() + secondaryTileset->numMetatiles())
return false;

return true;
Expand Down
2 changes: 1 addition & 1 deletion src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1445,7 +1445,7 @@ void MainWindow::on_actionNew_Tileset_triggered() {
}
mt->tiles.append(tile);
}
newSet.metatiles.append(mt);
newSet.addMetatile(mt);
}
for(int i = 0; i < 16; ++i) {
QList<QRgb> currentPal;
Expand Down
14 changes: 7 additions & 7 deletions src/project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ void Project::saveTilesetMetatileAttributes(Tileset *tileset) {
QFile attrs_file(tileset->metatile_attrs_path);
if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QByteArray data;
for (Metatile *metatile : tileset->metatiles) {
for (const auto &metatile : tileset->metatiles()) {
uint32_t attributes = metatile->getAttributes();
for (int i = 0; i < projectConfig.metatileAttributesSize; i++)
data.append(static_cast<char>(attributes >> (8 * i)));
Expand All @@ -1029,7 +1029,7 @@ void Project::saveTilesetMetatiles(Tileset *tileset) {
if (metatiles_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QByteArray data;
int numTiles = projectConfig.getNumTilesInMetatile();
for (Metatile *metatile : tileset->metatiles) {
for (const auto &metatile : tileset->metatiles()) {
for (int i = 0; i < numTiles; i++) {
uint16_t tile = metatile->tiles.at(i).rawValue();
data.append(static_cast<char>(tile));
Expand All @@ -1038,7 +1038,7 @@ void Project::saveTilesetMetatiles(Tileset *tileset) {
}
metatiles_file.write(data);
} else {
tileset->metatiles.clear();
tileset->clearMetatiles();
logError(QString("Could not open tileset metatiles file '%1'").arg(tileset->metatiles_path));
}
}
Expand Down Expand Up @@ -1522,16 +1522,16 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
}
metatiles.append(metatile);
}
tileset->metatiles = metatiles;
tileset->setMetatiles(metatiles);
} else {
tileset->metatiles.clear();
tileset->clearMetatiles();
logError(QString("Could not open tileset metatiles file '%1'").arg(tileset->metatiles_path));
}

QFile attrs_file(tileset->metatile_attrs_path);
if (attrs_file.open(QIODevice::ReadOnly)) {
QByteArray data = attrs_file.readAll();
int num_metatiles = tileset->metatiles.count();
int num_metatiles = tileset->numMetatiles();
int attrSize = projectConfig.metatileAttributesSize;
int num_metatileAttrs = data.length() / attrSize;
if (num_metatiles != num_metatileAttrs) {
Expand All @@ -1544,7 +1544,7 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
uint32_t attributes = 0;
for (int j = 0; j < attrSize; j++)
attributes |= static_cast<unsigned char>(data.at(i * attrSize + j)) << (8 * j);
tileset->metatiles.at(i)->setAttributes(attributes);
tileset->metatileAt(i)->setAttributes(attributes);
}
} else {
logError(QString("Could not open tileset metatile attributes file '%1'").arg(tileset->metatile_attrs_path));
Expand Down
4 changes: 2 additions & 2 deletions src/scriptapi/apimap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,13 +533,13 @@ QJSValue MainWindow::getSecondaryTilesetPalettesPreview() {
int MainWindow::getNumPrimaryTilesetMetatiles() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return 0;
return this->editor->map->layout->tileset_primary->metatiles.length();
return this->editor->map->layout->tileset_primary->numMetatiles();
}

int MainWindow::getNumSecondaryTilesetMetatiles() {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return 0;
return this->editor->map->layout->tileset_secondary->metatiles.length();
return this->editor->map->layout->tileset_secondary->numMetatiles();
}

int MainWindow::getNumPrimaryTilesetTiles() {
Expand Down
2 changes: 1 addition & 1 deletion src/ui/metatilelayersitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ void MetatileLayersItem::draw() {
QPainter painter(&pixmap);

// Draw tile images
int numTiles = projectConfig.getNumTilesInMetatile();
int numTiles = qMin(projectConfig.getNumTilesInMetatile(), this->metatile ? this->metatile->tiles.length() : 0);
for (int i = 0; i < numTiles; i++) {
Tile tile = this->metatile->tiles.at(i);
QImage tileImage = getPalettedTileImage(tile.tileId, this->primaryTileset, this->secondaryTileset, tile.palette, true)
Expand Down
10 changes: 5 additions & 5 deletions src/ui/metatileselector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ void MetatileSelector::draw() {
this->setPixmap(QPixmap());
}

int primaryLength = this->primaryTileset->metatiles.length();
int length_ = primaryLength + this->secondaryTileset->metatiles.length();
int primaryLength = this->primaryTileset->numMetatiles();
int length_ = primaryLength + this->secondaryTileset->numMetatiles();
int height_ = length_ / this->numMetatilesWide;
if (length_ % this->numMetatilesWide != 0) {
height_++;
Expand Down Expand Up @@ -199,10 +199,10 @@ void MetatileSelector::updateExternalSelectedMetatiles() {

uint16_t MetatileSelector::getMetatileId(int x, int y) const {
int index = y * this->numMetatilesWide + x;
if (index < this->primaryTileset->metatiles.length()) {
if (index < this->primaryTileset->numMetatiles()) {
return static_cast<uint16_t>(index);
} else {
return static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - this->primaryTileset->metatiles.length());
return static_cast<uint16_t>(Project::getNumMetatilesPrimary() + index - this->primaryTileset->numMetatiles());
}
}

Expand All @@ -215,7 +215,7 @@ QPoint MetatileSelector::getMetatileIdCoords(uint16_t metatileId) {

int index = metatileId < Project::getNumMetatilesPrimary()
? metatileId
: metatileId - Project::getNumMetatilesPrimary() + this->primaryTileset->metatiles.length();
: metatileId - Project::getNumMetatilesPrimary() + this->primaryTileset->numMetatiles();
return QPoint(index % this->numMetatilesWide, index / this->numMetatilesWide);
}

Expand Down
48 changes: 17 additions & 31 deletions src/ui/tileseteditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ TilesetEditor::~TilesetEditor()
delete tileSelector;
delete metatileLayersItem;
delete paletteEditor;
delete metatile;
delete primaryTileset;
delete secondaryTileset;
delete metatilesScene;
Expand All @@ -41,6 +40,7 @@ TilesetEditor::~TilesetEditor()
delete selectedTileScene;
delete metatileLayersScene;
delete copiedMetatile;
this->metatileHistory.clear();
}

void TilesetEditor::update(Map *map, QString primaryTilesetLabel, QString secondaryTilesetLabel) {
Expand Down Expand Up @@ -781,8 +781,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
secondarySpinBox->setMinimum(1);
primarySpinBox->setMaximum(Project::getNumMetatilesPrimary());
secondarySpinBox->setMaximum(Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary());
primarySpinBox->setValue(this->primaryTileset->metatiles.length());
secondarySpinBox->setValue(this->secondaryTileset->metatiles.length());
primarySpinBox->setValue(this->primaryTileset->numMetatiles());
secondarySpinBox->setValue(this->secondaryTileset->numMetatiles());
form.addRow(new QLabel("Primary Tileset"), primarySpinBox);
form.addRow(new QLabel("Secondary Tileset"), secondarySpinBox);

Expand All @@ -792,22 +792,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
form.addRow(&buttonBox);

if (dialog.exec() == QDialog::Accepted) {
int numPrimaryMetatiles = primarySpinBox->value();
int numSecondaryMetatiles = secondarySpinBox->value();
int numTiles = projectConfig.getNumTilesInMetatile();
while (this->primaryTileset->metatiles.length() > numPrimaryMetatiles) {
delete this->primaryTileset->metatiles.takeLast();
}
while (this->primaryTileset->metatiles.length() < numPrimaryMetatiles) {
this->primaryTileset->metatiles.append(new Metatile(numTiles));
}
while (this->secondaryTileset->metatiles.length() > numSecondaryMetatiles) {
delete this->secondaryTileset->metatiles.takeLast();
}
while (this->secondaryTileset->metatiles.length() < numSecondaryMetatiles) {
this->secondaryTileset->metatiles.append(new Metatile(numTiles));
}

this->primaryTileset->resizeMetatiles(primarySpinBox->value());
this->secondaryTileset->resizeMetatiles(secondarySpinBox->value());
this->metatileSelector->updateSelectedMetatile();
this->refresh();
this->hasUnsavedChanges = true;
Expand Down Expand Up @@ -1008,20 +994,20 @@ void TilesetEditor::importTilesetMetatiles(Tileset *tileset, bool primary)
// Revisit this when tiles and num metatiles are added to tileset editory history.
int metatileIdBase = primary ? 0 : Project::getNumMetatilesPrimary();
for (int i = 0; i < metatiles.length(); i++) {
if (i >= tileset->metatiles.length()) {
if (i >= tileset->numMetatiles()) {
break;
}

uint16_t metatileId = static_cast<uint16_t>(metatileIdBase + i);
QString prevLabel = Tileset::getOwnedMetatileLabel(metatileId, this->primaryTileset, this->secondaryTileset);
Metatile *prevMetatile = new Metatile(*tileset->metatiles.at(i));
Metatile *prevMetatile = new Metatile(*tileset->metatileAt(i));
MetatileHistoryItem *commit = new MetatileHistoryItem(metatileId,
prevMetatile, new Metatile(*metatiles.at(i)),
prevLabel, prevLabel);
metatileHistory.push(commit);
}

tileset->metatiles = metatiles;
tileset->setMetatiles(metatiles);
this->refresh();
this->hasUnsavedChanges = true;
}
Expand Down Expand Up @@ -1125,9 +1111,9 @@ void TilesetEditor::countTileUsage() {

// check primary tilesets that are used with this secondary tileset for
// reference to secondary tiles in primary metatiles
for (Tileset *tileset : primaryTilesets) {
for (Metatile *metatile : tileset->metatiles) {
for (Tile tile : metatile->tiles) {
for (const auto &tileset : primaryTilesets) {
for (const auto &metatile : tileset->metatiles()) {
for (const auto &tile : metatile->tiles) {
if (tile.tileId >= Project::getNumTilesPrimary())
this->tileSelector->usedTiles[tile.tileId]++;
}
Expand All @@ -1136,24 +1122,24 @@ void TilesetEditor::countTileUsage() {

// do the opposite for primary tiles in secondary metatiles
for (Tileset *tileset : secondaryTilesets) {
for (Metatile *metatile : tileset->metatiles) {
for (Tile tile : metatile->tiles) {
for (const auto &metatile : tileset->metatiles()) {
for (const auto &tile : metatile->tiles) {
if (tile.tileId < Project::getNumTilesPrimary())
this->tileSelector->usedTiles[tile.tileId]++;
}
}
}

// check this primary tileset metatiles
for (Metatile *metatile : this->primaryTileset->metatiles) {
for (Tile tile : metatile->tiles) {
for (const auto &metatile : this->primaryTileset->metatiles()) {
for (const auto &tile : metatile->tiles) {
this->tileSelector->usedTiles[tile.tileId]++;
}
}

// and the secondary metatiles
for (Metatile *metatile : this->secondaryTileset->metatiles) {
for (Tile tile : metatile->tiles) {
for (const auto &metatile : this->secondaryTileset->metatiles()) {
for (const auto &tile : metatile->tiles) {
this->tileSelector->usedTiles[tile.tileId]++;
}
}
Expand Down
Loading

0 comments on commit b05f1d9

Please sign in to comment.