Skip to content

Commit

Permalink
Use grid span instead of drawing everything directly
Browse files Browse the repository at this point in the history
Works way better with QT

Signed-off-by: Tomas Slusny <[email protected]>
  • Loading branch information
deathbeam committed Feb 3, 2025
1 parent 5dc367b commit 0e7a8cd
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 92 deletions.
38 changes: 38 additions & 0 deletions src/tiled/tilesetmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ int TilesetModel::rowCount(const QModelIndex &parent) const
if (parent.isValid())
return 0;

if (tileset()->isAtlas()) {
// Calculate total rows needed based on the furthest tile
int maxRow = 0;
const int gridSize = 16; // Or calculate based on tiles

for (Tile *tile : tileset()->tiles()) {
QRect rect = tile->imageRect();
int bottomRow = (rect.y() + rect.height() + gridSize - 1) / gridSize;
maxRow = std::max(maxRow, bottomRow);
}
return maxRow;
}

const int tileCount = mTileIds.size();
const int columns = columnCount();

Expand Down Expand Up @@ -285,4 +298,29 @@ void TilesetModel::refreshTileIds()
mTileIds.append(tile->id());
}

QSize TilesetModel::tileSpanSize(const QModelIndex &index) const
{
if (!tileset()->isAtlas())
return QSize(1, 1);

if (Tile *tile = tileAt(index)) {
const int gridSize = 16; // Same as used in rowCount
QRect rect = tile->imageRect();
return QSize((rect.width() + gridSize - 1) / gridSize,
(rect.height() + gridSize - 1) / gridSize);
}
return QSize(1, 1);
}

QPoint TilesetModel::tileGridPosition(const Tile *tile) const
{
if (!tileset()->isAtlas())
return QPoint(0, 0);

const int gridSize = 16;
QRect rect = tile->imageRect();
return QPoint(rect.x() / gridSize,
rect.y() / gridSize);
}

#include "moc_tilesetmodel.cpp"
11 changes: 11 additions & 0 deletions src/tiled/tilesetmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ class TilesetModel : public QAbstractListModel

void setColumnCountOverride(int columnCount);

/**
* Returns the size of cells spanned by the tile at given index.
* Used for atlas tilesets to allow tiles to span multiple cells.
*/
QSize tileSpanSize(const QModelIndex &index) const;

/**
* Returns grid position for the tile. Used for atlas tilesets.
*/
QPoint tileGridPosition(const Tile *tile) const;

public slots:
/**
* Should be called when anything changes about the given \a tiles that
Expand Down
135 changes: 45 additions & 90 deletions src/tiled/tilesetview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,42 +114,37 @@ void TileDelegate::paint(QPainter *painter,
return;

const QPixmap &tileImage = tile->image();
const bool isAtlas = tile->tileset()->isAtlas();
const int extra = mTilesetView->drawGrid() ? 1 : 0;
const qreal zoom = mTilesetView->scale();
const bool wrapping = mTilesetView->dynamicWrapping();

QRect imageRect = tile->imageRect();
QSize tileSize = imageRect.size().isValid() ? imageRect.size() : tile->size();
QSize tileSize = tile->size();
if (tileImage.isNull()) {
Tileset *tileset = model->tileset();
if (tileset->isCollection()) {
tileSize = QSize(32, 32);
} else {
int max = std::max(tileset->tileWidth(), tileset->tileHeight());
int min = std::min(max, 32);
tileSize = QSize(min, min);
}
}

// For atlas tilesets, use the actual position from imageRect
QRect targetRect;
if (isAtlas) {
// Account for scrollbar positions
const QPoint scrollOffset(mTilesetView->horizontalScrollBar()->value(),
mTilesetView->verticalScrollBar()->value());
// Compute rectangle to draw the image in: bottom- and left-aligned
QRect targetRect = option.rect.adjusted(0, 0, -extra, -extra);

// Convert atlas coordinates to view coordinates
QPoint viewPos = (imageRect.topLeft() * zoom) - scrollOffset;
targetRect = QRect(viewPos, imageRect.size() * zoom);
if (wrapping) {
qreal scale = std::min(static_cast<qreal>(targetRect.width()) / tileSize.width(),
static_cast<qreal>(targetRect.height()) / tileSize.height());
tileSize *= scale;

// Offset by the view's margin/padding if any
// targetRect = targetRect.adjusted(0, 0, -extra, -extra);
auto center = targetRect.center();
targetRect.setSize(tileSize);
targetRect.moveCenter(center);
} else {
// Original grid-based positioning for non-atlas tilesets
targetRect = option.rect.adjusted(0, 0, -extra, -extra);

if (mTilesetView->dynamicWrapping()) {
qreal scale = std::min(static_cast<qreal>(targetRect.width()) / tileSize.width(),
static_cast<qreal>(targetRect.height()) / tileSize.height());
tileSize *= scale;

auto center = targetRect.center();
targetRect.setSize(tileSize);
targetRect.moveCenter(center);
} else {
tileSize *= zoom;
targetRect.setSize(tileSize);
}
tileSize *= zoom;
targetRect.setTop(targetRect.bottom() - tileSize.height() + 1);
targetRect.setRight(targetRect.left() + tileSize.width() - 1);
}

// Draw the tile image
Expand All @@ -158,10 +153,11 @@ void TileDelegate::paint(QPainter *painter,
painter->setRenderHint(QPainter::SmoothPixmapTransform);

if (!tileImage.isNull())
painter->drawPixmap(targetRect, tileImage, imageRect);
painter->drawPixmap(targetRect, tileImage, tile->imageRect());
else
mTilesetView->imageMissingIcon().paint(painter, targetRect, Qt::AlignBottom | Qt::AlignLeft);


// Overlay with film strip when animated
if (mTilesetView->markAnimatedTiles() && tile->isAnimated())
drawFilmStrip(painter, targetRect);
Expand Down Expand Up @@ -356,11 +352,6 @@ int TilesetView::sizeHintForColumn(int column) const
const TilesetModel *model = tilesetModel();
if (!model)
return -1;
if (model->tileset()->isAtlas()) {
// Get the tile at this column and use its width
if (Tile *tile = model->tileAt(model->index(0, column)))
return tile->imageRect().width() * scale();
}
if (model->tileset()->isCollection())
return QTableView::sizeHintForColumn(column);

Expand All @@ -378,11 +369,6 @@ int TilesetView::sizeHintForRow(int row) const
const TilesetModel *model = tilesetModel();
if (!model)
return -1;
if (model->tileset()->isAtlas()) {
// Get the tile at this row and use its height
if (Tile *tile = model->tileAt(model->index(row, 0)))
return tile->imageRect().height() * scale();
}
if (model->tileset()->isCollection())
return QTableView::sizeHintForRow(row);

Expand Down Expand Up @@ -431,8 +417,25 @@ bool TilesetView::dynamicWrapping() const
void TilesetView::setModel(QAbstractItemModel *model)
{
QTableView::setModel(model);

if (TilesetModel *tilesetModel = qobject_cast<TilesetModel*>(model)) {
if (tilesetModel->tileset()->isAtlas()) {
// Set up spans for atlas tiles
for (Tile *tile : tilesetModel->tileset()->tiles()) {
QModelIndex index = tilesetModel->tileIndex(tile);
if (index.isValid()) {
QSize span = tilesetModel->tileSpanSize(index);
if (span != QSize(1, 1))
setSpan(index.row(), index.column(),
span.height(), span.width());
}
}
}
}

updateBackgroundColor();
setVerticalScrollBarPolicy(dynamicWrapping() ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAsNeeded);
setVerticalScrollBarPolicy(dynamicWrapping() ? Qt::ScrollBarAlwaysOn
: Qt::ScrollBarAsNeeded);
refreshColumnCount();
}

Expand Down Expand Up @@ -511,54 +514,6 @@ void TilesetView::keyPressEvent(QKeyEvent *event)
return QTableView::keyPressEvent(event);
}

QModelIndex TilesetView::indexAt(const QPoint &point) const
{
if (!tilesetModel())
return QModelIndex();

if (tilesetModel()->tileset()->isAtlas()) {
// Convert view coordinates to atlas coordinates
const QPoint scrollOffset(horizontalScrollBar()->value(),
verticalScrollBar()->value());
const QPointF atlasPos = (point + scrollOffset) / scale();

for (const Tile *tile : tilesetModel()->tileset()->tiles()) {
if (tile->imageRect().contains(atlasPos.toPoint()))
return tilesetModel()->tileIndex(tile);
}

return QModelIndex();
}

// Original grid-based indexAt logic
return QTableView::indexAt(point);
}

QRect TilesetView::visualRect(const QModelIndex &index) const
{
if (!tilesetModel())
return QRect();

if (tilesetModel()->tileset()->isAtlas()) {
if (Tile *tile = tilesetModel()->tileAt(index)) {
const QRect imageRect = tile->imageRect();
const QPoint scrollOffset(horizontalScrollBar()->value(),
verticalScrollBar()->value());

// Convert atlas coordinates to view coordinates
QRect rect(imageRect.topLeft() * scale() - scrollOffset,
imageRect.size() * scale());

return rect;
// const int extra = drawGrid() ? 1 : 0;
// return rect.adjusted(0, 0, -extra, -extra);
}
return QRect();
}

return QTableView::visualRect(index);
}

void TilesetView::setRelocateTiles(bool enabled)
{
if (mRelocateTiles == enabled)
Expand Down Expand Up @@ -957,7 +912,7 @@ void TilesetView::refreshColumnCount()
if (!tilesetModel())
return;

if (!dynamicWrapping() || tilesetModel()->tileset()->isAtlas()) {
if (!dynamicWrapping()) {
tilesetModel()->setColumnCountOverride(0);
return;
}
Expand Down
2 changes: 0 additions & 2 deletions src/tiled/tilesetview.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ class TilesetView : public QTableView
void wheelEvent(QWheelEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
QModelIndex indexAt(const QPoint &point) const override;
QRect visualRect(const QModelIndex &index) const override;

private:
void onChange(const ChangeEvent &change);
Expand Down

0 comments on commit 0e7a8cd

Please sign in to comment.