Skip to content

Commit

Permalink
Switch to old tileid format
Browse files Browse the repository at this point in the history
Signed-off-by: Tomas Slusny <[email protected]>
  • Loading branch information
deathbeam committed Feb 9, 2025
1 parent 24c208a commit ccb4fd2
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 81 deletions.
49 changes: 31 additions & 18 deletions src/libtiled/tileset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ bool Tileset::initializeTilesetTiles()

for (int tileNum = 0; tileNum < tileRects.size(); ++tileNum) {
QRect rect = tileRects.at(tileNum);
const int tileId = isAtlas() ? generateTileId(rect.x(), rect.y(), true) : tileNum;
const int tileId = tileNum;
auto it = mTilesById.find(tileId);
if (it != mTilesById.end()) {
it.value()->setImage(QPixmap()); // make sure it uses the tileset's image
Expand Down Expand Up @@ -471,9 +471,6 @@ void Tileset::addTiles(const QList<Tile *> &tiles)
Q_ASSERT(tile->tileset() == this && !mTilesById.contains(tile->id()));
mTilesById.insert(tile->id(), tile);
mTiles.append(tile);

if (isAtlas())
mNextTileId = std::max(mNextTileId, tile->id() + 1);
}

updateTileSize();
Expand Down Expand Up @@ -721,24 +718,40 @@ void Tileset::updateTileSize()
mTileHeight = maxHeight;
}

int Tileset::generateTileId(int x, int y, bool absolute) const {
if (absolute) {
// Normalize x and y to tile coordinates
x = qRound(qreal(x - mMargin) / (mTileWidth + mTileSpacing));
y = qRound(qreal(y - mMargin) / (mTileHeight + mTileSpacing));
}
QPoint Tileset::pixelToGrid(const QPoint &pixelPos) const
{
return QPoint(
(pixelPos.x() - mMargin) / (mTileWidth + mTileSpacing),
(pixelPos.y() - mMargin) / (mTileHeight + mTileSpacing)
);
}

// Use 12+12 bit spatial hash (4096x4096 coordinates limit)
x &= 0xFFF;
y &= 0xFFF;
return (x << 12) | y; // 24 bits total
QPoint Tileset::gridToPixel(const QPoint &gridPos) const
{
return QPoint(
mMargin + gridPos.x() * (mTileWidth + mTileSpacing),
mMargin + gridPos.y() * (mTileHeight + mTileSpacing)
);
}

QRect Tileset::pixelToGrid(const QRect &pixelRect) const
{
const QPoint topLeft = pixelToGrid(pixelRect.topLeft());
const QSize size(
pixelRect.width() / mTileWidth,
pixelRect.height() / mTileHeight
);
return QRect(topLeft, size);
}

QPoint Tileset::generateTilePos(int id) const
QRect Tileset::gridToPixel(const QRect &gridRect) const
{
const int x = (id >> 12) & 0xFFF;
const int y = id & 0xFFF;
return QPoint(x, y);
const QPoint topLeft = gridToPixel(gridRect.topLeft());
return QRect(
topLeft.x(), topLeft.y(),
gridRect.width() * mTileWidth,
gridRect.height() * mTileHeight
);
}

QString Tileset::orientationToString(Tileset::Orientation orientation)
Expand Down
14 changes: 5 additions & 9 deletions src/libtiled/tileset.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,11 @@ class TILEDSHARED_EXPORT Tileset : public Object, public QEnableSharedFromThis<T
int nextTileId() const;
int takeNextTileId();

/**
* Generates a tile ID from grid column and row coordinates or absolute coordinates
*/
int generateTileId(int x, int y, bool absolute = false) const;

/**
* Generates a grid position from a tile ID.
*/
QPoint generateTilePos(int id) const;
// Convert between pixel and grid coordinates
QPoint pixelToGrid(const QPoint &pixelPos) const;
QPoint gridToPixel(const QPoint &gridPos) const;
QRect pixelToGrid(const QRect &pixelRect) const;
QRect gridToPixel(const QRect &gridRect) const;

void setTileImage(Tile *tile,
const QPixmap &image,
Expand Down
12 changes: 7 additions & 5 deletions src/tiled/tilesetmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,25 +270,27 @@ Tile *TilesetModel::tileAt(const QModelIndex &index) const

if (tileset()->isAtlas()) {
const QPoint atlasPos = viewToAtlasCoords(index.column(), index.row());
const int tileId = tileset()->generateTileId(atlasPos.x(), atlasPos.y());
return tileset()->findTile(tileId);
for (Tile *tile : tileset()->tiles()) {
const QPoint tilePos = tileset()->pixelToGrid(tile->imageRect().topLeft());
if (tilePos == atlasPos)
return tile;
}
return nullptr;
}

const int tileIndex = index.column() + index.row() * columnCount();

if (tileIndex < mTileIds.size()) {
const int tileId = mTileIds.at(tileIndex);
return tileset()->findTile(tileId);
}

return nullptr;
}

QModelIndex TilesetModel::tileIndex(const Tile *tile) const
{
Q_ASSERT(tile->tileset() == tileset());
if (tileset()->isAtlas()) {
const QPoint tilePos = tileset()->generateTilePos(tile->id());
const QPoint tilePos = tileset()->pixelToGrid(tile->imageRect().topLeft());
const QPoint viewPos = atlasToViewCoords(tilePos.x(), tilePos.y());
return index(viewPos.y(), viewPos.x());
}
Expand Down
75 changes: 26 additions & 49 deletions src/tiled/tilesetview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1100,16 +1100,8 @@ void TilesetView::mergeSpan(int minRow, int maxRow, int minCol, int maxCol)
QModelIndex topLeftIndex = m->index(minRow, minCol);
Tile *targetTile = m->tileAt(topLeftIndex);

// Convert to pixel coordinates only for the final imageRect
const int tileWidth = tileset->tileWidth();
const int tileHeight = tileset->tileHeight();
const int spacing = tileset->tileSpacing();
const int margin = tileset->margin();

QRect mergeRect(margin + topLeft.x() * (tileWidth + spacing),
margin + topLeft.y() * (tileHeight + spacing),
spanSize.width() * tileWidth,
spanSize.height() * tileHeight);
// Convert to pixel coordinates for the final imageRect
QRect mergeRect = tileset->gridToPixel(QRect(topLeft, spanSize));

// Collect all tiles within the merge rectangle except the target tile
QList<Tile*> tilesToRemove;
Expand All @@ -1128,12 +1120,11 @@ void TilesetView::mergeSpan(int minRow, int maxRow, int minCol, int maxCol)
if (targetTile) {
// Extend the existing tile's span
mTilesetDocument->undoStack()->push(new ChangeTileImageRect(mTilesetDocument,
QList<Tile*>() << targetTile,
QVector<QRect>() << mergeRect));
QList<Tile*>() << targetTile,
QVector<QRect>() << mergeRect));
} else {
// Create a new spanning tile
const int tileId = tileset->generateTileId(minCol, minRow);
Tile *newTile = new Tile(tileId, tileset);
Tile *newTile = new Tile(tileset->takeNextTileId(), tileset);
newTile->setImageRect(mergeRect);
mTilesetDocument->undoStack()->push(new AddTiles(mTilesetDocument, QList<Tile*>() << newTile));
}
Expand All @@ -1148,11 +1139,12 @@ void TilesetView::splitSpan(Tile *spanTile, int relativeRow, int relativeCol)
Tileset *tileset = m->tileset();

// Get base grid position
QModelIndex tilePos = m->tileIndex(spanTile);
const QPoint basePos(tilePos.column(), tilePos.row());
const QPoint basePos = tileset->pixelToGrid(spanTile->imageRect().topLeft());

// Calculate span in grid coordinates
QSize span = m->tileSpanSize(tilePos);
const QRect spanRect = tileset->pixelToGrid(spanTile->imageRect());
const QSize span = spanRect.size();

if (span.width() <= 0 || span.height() <= 0 ||
relativeCol < 0 || relativeCol >= span.width() ||
relativeRow < 0 || relativeRow >= span.height())
Expand All @@ -1173,44 +1165,31 @@ void TilesetView::splitSpan(Tile *spanTile, int relativeRow, int relativeCol)
if (minDist == distToLeft) {
// Keep right side as span
newSpanGridRect = QRect(basePos.x() + relativeCol + 1, basePos.y(),
span.width() - relativeCol - 1, span.height());
span.width() - relativeCol - 1, span.height());
splitGridRect = QRect(basePos.x(), basePos.y(),
relativeCol + 1, span.height());
} else if (minDist == distToRight) {
// Keep left side as span
newSpanGridRect = QRect(basePos.x(), basePos.y(),
relativeCol, span.height());
relativeCol, span.height());
splitGridRect = QRect(basePos.x() + relativeCol, basePos.y(),
span.width() - relativeCol, span.height());
} else if (minDist == distToTop) {
// Keep bottom as span
newSpanGridRect = QRect(basePos.x(), basePos.y() + relativeRow + 1,
span.width(), span.height() - relativeRow - 1);
span.width(), span.height() - relativeRow - 1);
splitGridRect = QRect(basePos.x(), basePos.y(),
span.width(), relativeRow + 1);
} else {
// Keep top as span
newSpanGridRect = QRect(basePos.x(), basePos.y(),
span.width(), relativeRow);
span.width(), relativeRow);
splitGridRect = QRect(basePos.x(), basePos.y() + relativeRow,
span.width(), span.height() - relativeRow);
}

// Convert to pixel coordinates
const int tileWidth = tileset->tileWidth();
const int tileHeight = tileset->tileHeight();
const int spacing = tileset->tileSpacing();
const int margin = tileset->margin();

auto toPixelRect = [=](const QRect &gridRect) {
return QRect(margin + gridRect.x() * (tileWidth + spacing),
margin + gridRect.y() * (tileHeight + spacing),
gridRect.width() * tileWidth,
gridRect.height() * tileHeight);
};

QRect newSpanRect = toPixelRect(newSpanGridRect);
QRect splitRect = toPixelRect(splitGridRect);
QRect newSpanRect = tileset->gridToPixel(newSpanGridRect);
QRect splitRect = tileset->gridToPixel(splitGridRect);

mTilesetDocument->undoStack()->beginMacro(tr("Split Tiles"));

Expand All @@ -1229,39 +1208,37 @@ void TilesetView::splitSpan(Tile *spanTile, int relativeRow, int relativeCol)
const QPoint spanTilePos = spanTile->imageRect().topLeft();
if (splitRect.contains(spanTilePos)) {
// Resize original tile to single tile
QRect newSpanTileRect(spanTilePos.x(), spanTilePos.y(), tileWidth, tileHeight);
const QRect newSpanTileRect = tileset->gridToPixel(QRect(
tileset->pixelToGrid(spanTilePos), QSize(1, 1)));
mTilesetDocument->undoStack()->push(new ChangeTileImageRect(mTilesetDocument,
QList<Tile*>() << spanTile,
QVector<QRect>() << newSpanTileRect));
QList<Tile*>() << spanTile,
QVector<QRect>() << newSpanTileRect));

// Create new span in the remaining area
if (!newSpanGridRect.isEmpty()) {
const int tileId = tileset->generateTileId(newSpanGridRect.x(), newSpanGridRect.y());
Tile *newSpan = new Tile(tileId, tileset);
Tile *newSpan = new Tile(tileset->takeNextTileId(), tileset);
newSpan->setImageRect(newSpanRect);
mTilesetDocument->undoStack()->push(new AddTiles(mTilesetDocument, QList<Tile*>() << newSpan));
}
} else {
// Adjust span to new size
mTilesetDocument->undoStack()->push(new ChangeTileImageRect(mTilesetDocument,
QList<Tile*>() << spanTile,
QVector<QRect>() << newSpanRect));
QList<Tile*>() << spanTile,
QVector<QRect>() << newSpanRect));
}

// Create individual tiles for split area
QList<Tile*> newTiles;
for (int r = 0; r < splitGridRect.height(); ++r) {
for (int c = 0; c < splitGridRect.width(); ++c) {
const int gridX = splitGridRect.x() + c;
const int gridY = splitGridRect.y() + r;
const int tileId = tileset->generateTileId(gridX, gridY);
const QPoint gridPos(splitGridRect.x() + c, splitGridRect.y() + r);

// Skip the original tile position
if (tileId == spanTile->id())
if (tileset->pixelToGrid(spanTilePos) == gridPos)
continue;

Tile *newTile = new Tile(tileId, tileset);
newTile->setImageRect(toPixelRect(QRect(gridX, gridY, 1, 1)));
Tile *newTile = new Tile(tileset->takeNextTileId(), tileset);
newTile->setImageRect(tileset->gridToPixel(QRect(gridPos, QSize(1, 1))));
newTiles.append(newTile);
}
}
Expand Down

0 comments on commit ccb4fd2

Please sign in to comment.