Add get/setMetatileTiles array functions to API

This commit is contained in:
GriffinR 2021-11-24 00:29:58 -05:00 committed by huderlem
parent 6613318900
commit ebd7af8846
2 changed files with 76 additions and 34 deletions

View file

@ -127,7 +127,11 @@ public:
Q_INVOKABLE void setMetatileBehavior(int metatileId, int behavior); Q_INVOKABLE void setMetatileBehavior(int metatileId, int behavior);
Q_INVOKABLE QJSValue getMetatileTile(int metatileId, int tileIndex); Q_INVOKABLE QJSValue getMetatileTile(int metatileId, int tileIndex);
Q_INVOKABLE void setMetatileTile(int metatileId, int tileIndex, int tileId, bool xflip, bool yflip, int palette, bool forceRedraw = true); Q_INVOKABLE void setMetatileTile(int metatileId, int tileIndex, int tileId, bool xflip, bool yflip, int palette, bool forceRedraw = true);
Q_INVOKABLE void setMetatileTile(int metatileId, int tileIndex, QJSValue obj, bool forceRedraw = true); Q_INVOKABLE void setMetatileTile(int metatileId, int tileIndex, QJSValue tileObj, bool forceRedraw = true);
int calculateTileBounds(int * tileStart, int * tileEnd);
Q_INVOKABLE QJSValue getMetatileTiles(int metatileId, int tileStart = 0, int tileEnd = -1);
Q_INVOKABLE void setMetatileTiles(int metatileId, QJSValue tilesObj, int tileStart = 0, int tileEnd = -1, bool forceRedraw = true);
Q_INVOKABLE void setMetatileTiles(int metatileId, int tileId, bool xflip, bool yflip, int palette, int tileStart = 0, int tileEnd = -1, bool forceRedraw = true);
private slots: private slots:

View file

@ -14,6 +14,14 @@ QJSValue MainWindow::getBlock(int x, int y) {
return Scripting::fromBlock(block); return Scripting::fromBlock(block);
} }
// TODO: "needsFullRedraw" is used when redrawing the map after
// changing a metatile's tiles via script. It is unnecessarily
// resource intensive. The map metatiles that need to be updated are
// not marked as changed, so they will not be redrawn if the cache
// isn't ignored. Ideally the setMetatileTiles functions would properly
// set each of the map spaces that use the modified metatile so that
// the cache could be used, though this would lkely still require a
// full read of the map and its border/connections.
void MainWindow::tryRedrawMapArea(bool forceRedraw) { void MainWindow::tryRedrawMapArea(bool forceRedraw) {
if (!forceRedraw) return; if (!forceRedraw) return;
@ -64,7 +72,7 @@ int MainWindow::getMetatileId(int x, int y) {
if (!this->editor->map->getBlock(x, y, &block)) { if (!this->editor->map->getBlock(x, y, &block)) {
return 0; return 0;
} }
return block.tile; return block.metatileId;
} }
void MainWindow::setMetatileId(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) { void MainWindow::setMetatileId(int x, int y, int metatileId, bool forceRedraw, bool commitChanges) {
@ -96,7 +104,7 @@ void MainWindow::setCollision(int x, int y, int collision, bool forceRedraw, boo
if (!this->editor->map->getBlock(x, y, &block)) { if (!this->editor->map->getBlock(x, y, &block)) {
return; return;
} }
this->editor->map->setBlock(x, y, Block(block.tile, collision, block.elevation)); this->editor->map->setBlock(x, y, Block(block.metatileId, collision, block.elevation));
this->tryCommitMapChanges(commitChanges); this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw); this->tryRedrawMapArea(forceRedraw);
} }
@ -118,7 +126,7 @@ void MainWindow::setElevation(int x, int y, int elevation, bool forceRedraw, boo
if (!this->editor->map->getBlock(x, y, &block)) { if (!this->editor->map->getBlock(x, y, &block)) {
return; return;
} }
this->editor->map->setBlock(x, y, Block(block.tile, block.collision, elevation)); this->editor->map->setBlock(x, y, Block(block.metatileId, block.collision, elevation));
this->tryCommitMapChanges(commitChanges); this->tryCommitMapChanges(commitChanges);
this->tryRedrawMapArea(forceRedraw); this->tryRedrawMapArea(forceRedraw);
} }
@ -667,44 +675,74 @@ void MainWindow::setMetatileBehavior(int metatileId, int behavior) {
this->saveMetatileAttributesByMetatileId(metatileId); this->saveMetatileAttributesByMetatileId(metatileId);
} }
QJSValue MainWindow::getMetatileTile(int metatileId, int tileIndex) { int MainWindow::calculateTileBounds(int * tileStart, int * tileEnd) {
Metatile * metatile = this->getMetatile(metatileId); int maxNumTiles = projectConfig.getTripleLayerMetatilesEnabled() ? 12 : 8;
int maxTileIndex = projectConfig.getTripleLayerMetatilesEnabled() ? 12 : 8; if (*tileEnd >= maxNumTiles || *tileEnd < 0)
if (!metatile || tileIndex >= maxTileIndex || tileIndex < 0) *tileEnd = maxNumTiles - 1;
return QJSValue(); if (*tileStart >= maxNumTiles || *tileStart < 0)
return Scripting::fromTile(metatile->tiles[tileIndex]); *tileStart = 0;
return 1 + (*tileEnd - *tileStart);
} }
void MainWindow::setMetatileTile(int metatileId, int tileIndex, int tileId, bool xflip, bool yflip, int palette, bool forceRedraw) { QJSValue MainWindow::getMetatileTiles(int metatileId, int tileStart, int tileEnd) {
Metatile * metatile = this->getMetatile(metatileId); Metatile * metatile = this->getMetatile(metatileId);
int maxTileIndex = projectConfig.getTripleLayerMetatilesEnabled() ? 12 : 8; int numTiles = calculateTileBounds(&tileStart, &tileEnd);
if (!metatile || tileIndex >= maxTileIndex || tileIndex < 0) if (!metatile || numTiles <= 0)
return; return QJSValue();
Tile * tile = &metatile->tiles[tileIndex];
if (!tile) return; QJSValue tiles = Scripting::getEngine()->newArray(numTiles);
if (tile->tile == tileId for (int i = 0; i < numTiles; i++, tileStart++)
&& tile->xflip == xflip tiles.setProperty(i, Scripting::fromTile(metatile->tiles[tileStart]));
&& tile->yflip == yflip return tiles;
&& tile->palette == palette) }
void MainWindow::setMetatileTiles(int metatileId, QJSValue tilesObj, int tileStart, int tileEnd, bool forceRedraw) {
Metatile * metatile = this->getMetatile(metatileId);
int numTiles = calculateTileBounds(&tileStart, &tileEnd);
if (!metatile || numTiles <= 0)
return; return;
tile->tile = tileId; // Write to metatile using as many of the given Tiles as possible
tile->xflip = xflip; int numTileObjs = qMin(tilesObj.property("length").toInt(), numTiles);
tile->yflip = yflip; int i = 0;
tile->palette = palette; for (; i < numTileObjs; i++)
metatile->tiles[i] = Scripting::toTile(tilesObj.property(i));
// Fill remainder of specified length with empty Tiles
for (; i < numTiles; i++)
metatile->tiles[i] = Tile();
this->saveMetatilesByMetatileId(metatileId); this->saveMetatilesByMetatileId(metatileId);
// TODO: Making tryRedrawMapArea do a full draw is unnecessarily expensive.
// The map metatiles that need to be updated are not changed by the above
// operation, so they will not be redrawn if the cache isn't ignored.
// Ideally setMetatileTile would properly set each of the map spaces that
// use this metatile so that the cache could be used, though this would
// likely still require a full read of the map and its border/connections.
this->needsFullRedraw = true; this->needsFullRedraw = true;
this->tryRedrawMapArea(forceRedraw); this->tryRedrawMapArea(forceRedraw);
} }
void MainWindow::setMetatileTile(int metatileId, int tileIndex, QJSValue obj, bool forceRedraw) { void MainWindow::setMetatileTiles(int metatileId, int tileId, bool xflip, bool yflip, int palette, int tileStart, int tileEnd, bool forceRedraw) {
Tile tile = Scripting::toTile(obj); Metatile * metatile = this->getMetatile(metatileId);
this->setMetatileTile(metatileId, tileIndex, tile.tile, tile.xflip, tile.yflip, tile.palette, forceRedraw); int numTiles = calculateTileBounds(&tileStart, &tileEnd);
if (!metatile || numTiles <= 0)
return;
// Write to metatile using Tiles of the specified value
Tile tile = Tile(tileId, xflip, yflip, palette);
for (int i = 0; i < numTiles; i++)
metatile->tiles[i] = tile;
this->saveMetatilesByMetatileId(metatileId);
this->needsFullRedraw = true;
this->tryRedrawMapArea(forceRedraw);
}
QJSValue MainWindow::getMetatileTile(int metatileId, int tileIndex) {
QJSValue tilesObj = this->getMetatileTiles(metatileId, tileIndex, tileIndex);
return tilesObj.property(0);
}
void MainWindow::setMetatileTile(int metatileId, int tileIndex, int tileId, bool xflip, bool yflip, int palette, bool forceRedraw) {
this->setMetatileTiles(metatileId, tileId, xflip, yflip, palette, tileIndex, tileIndex, forceRedraw);
}
void MainWindow::setMetatileTile(int metatileId, int tileIndex, QJSValue tileObj, bool forceRedraw) {
Tile tile = Scripting::toTile(tileObj);
this->setMetatileTiles(metatileId, tile.tileId, tile.xflip, tile.yflip, tile.palette, tileIndex, tileIndex, forceRedraw);
} }