diff --git a/src/tiledquick/qml/main.qml b/src/tiledquick/qml/main.qml index d67909eac4..def9315685 100644 --- a/src/tiledquick/qml/main.qml +++ b/src/tiledquick/qml/main.qml @@ -14,9 +14,21 @@ ApplicationWindow { height: 720 minimumWidth: 480 minimumHeight: 320 - title: qsTr("Tiled Quick") + title: qsTr("Tiled Quick | %1 | %2").arg(mapItem.visibleArea).arg(coordsText) visible: true + property string coordsText: { + if (mapLoader.status === Tiled.MapLoader.Null) { + return qsTr("No map file loaded") + } else if (mapLoader.status === Tiled.MapLoader.Error) { + return mapLoader.error + } else { + var mapRelativeCoords = singleFingerPanArea.mapToItem(mapItem, singleFingerPanArea.mouseX, singleFingerPanArea.mouseY) + var tileCoords = mapItem.screenToTileCoords(mapRelativeCoords.x, mapRelativeCoords.y) + return Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y) + } + } + FontLoader { id: fontAwesomeLoader source: "fonts/fontawesome.ttf" @@ -116,9 +128,11 @@ ApplicationWindow { id: mapLoader } - Item { + Rectangle { id: mapView + color: "#aaff0000" anchors.fill: parent + anchors.margins: 100 Item { id: mapContainer @@ -190,22 +204,4 @@ ApplicationWindow { containerAnimation.start() } } - - footer: Pane { - RowLayout { - Label { - text: { - if (mapLoader.status === Tiled.MapLoader.Null) { - qsTr("No map file loaded") - } else if (mapLoader.status === Tiled.MapLoader.Error) { - mapLoader.error - } else { - var mapRelativeCoords = singleFingerPanArea.mapToItem(mapItem, singleFingerPanArea.mouseX, singleFingerPanArea.mouseY) - var tileCoords = mapItem.screenToTileCoords(mapRelativeCoords.x, mapRelativeCoords.y) - Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y) - } - } - } - } - } } diff --git a/src/tiledquickplugin/tilelayeritem.cpp b/src/tiledquickplugin/tilelayeritem.cpp index 7380b69a48..0072e9af7a 100644 --- a/src/tiledquickplugin/tilelayeritem.cpp +++ b/src/tiledquickplugin/tilelayeritem.cpp @@ -185,11 +185,11 @@ class IsometricRenderHelper QSGNode *parent, const MapItem *mapItem, const TileLayer *layer, - const QRect &rect) : + const QRect &visibleScreenRect) : mRenderer(renderer), mParent(parent), mLayer(layer), - mRect(rect), + mVisibleScreenRect(visibleScreenRect), mTilesetHelper(mapItem), mTileWidth(mapItem->map()->tileWidth()), mTileHeight(mapItem->map()->tileHeight()) @@ -204,7 +204,7 @@ class IsometricRenderHelper Tiled::MapRenderer *mRenderer; QSGNode *mParent; const TileLayer *mLayer; - const QRect mRect; + const QRect mVisibleScreenRect; TilesetHelper mTilesetHelper; const int mTileWidth; const int mTileHeight; @@ -251,33 +251,86 @@ void IsometricRenderHelper::appendTileData(int x, int y) mTileData.append(data); } -// TODO: make this function work with a subset of the entire layer rect +// Mostly copied from IsometricRenderer::drawTileLayer(). void IsometricRenderHelper::addTilesToNode() { - if (mRect.isEmpty()) + if (mVisibleScreenRect.isEmpty()) return; - mTileData.reserve(TilesNode::MaxTileCount); - - for (int y = mRect.top(); y <= mRect.bottom(); ++y) { - int _x = mRect.left(); - int _y = y; + if (mTileWidth <= 0 || mTileHeight <= 1) + return; - while (_x <= mRect.right() && _y >= mRect.top()) { - appendTileData(_x, _y); - ++_x; - --_y; + QRect rect = mVisibleScreenRect; + if (rect.isNull()) + rect = mRenderer->boundingRect(mLayer->bounds()); + + QMargins drawMargins = mLayer->drawMargins(); + drawMargins.setTop(drawMargins.top() - mTileHeight); + drawMargins.setRight(drawMargins.right() - mTileWidth); + + rect.adjust(-drawMargins.right(), + -drawMargins.bottom(), + drawMargins.left(), + drawMargins.top()); + + // Determine the tile and pixel coordinates to start at + QPointF tilePos = mRenderer->screenToTileCoords(rect.x(), rect.y()); + QPoint rowItr = QPoint(qFloor(tilePos.x()), + qFloor(tilePos.y())); + QPointF startPos = mRenderer->tileToScreenCoords(rowItr); + startPos.rx() -= mTileWidth / 2; + startPos.ry() += mTileHeight; + + // Compensate for the layer position + rowItr -= QPoint(mLayer->x(), mLayer->y()); + + /* Determine in which half of the tile the top-left corner of the area we + * need to draw is. If we're in the upper half, we need to start one row + * up due to those tiles being visible as well. How we go up one row + * depends on whether we're in the left or right half of the tile. + */ + const bool inUpperHalf = startPos.y() - rect.y() > mTileHeight / 2; + const bool inLeftHalf = rect.x() - startPos.x() < mTileWidth / 2; + + if (inUpperHalf) { + if (inLeftHalf) { + --rowItr.rx(); + startPos.rx() -= mTileWidth / 2; + } else { + --rowItr.ry(); + startPos.rx() += mTileWidth / 2; } + startPos.ry() -= mTileHeight / 2; } - for (int x = mRect.left() + 1; x <= mRect.right(); ++x) { - int _x = x; - int _y = mRect.bottom(); + // Determine whether the current row is shifted half a tile to the right + bool shifted = inUpperHalf ^ inLeftHalf; + + mTileData.reserve(TilesNode::MaxTileCount); + + for (int y = static_cast(startPos.y() * 2); y - mTileHeight * 2 < rect.bottom() * 2; y += mTileHeight) { + QPoint columnItr = rowItr; - while (_x <= mRect.right() && _y >= mRect.top()) { - appendTileData(_x, _y); - ++_x; - --_y; + for (int x = static_cast(startPos.x()); x < rect.right(); x += mTileWidth) { + const Cell &cell = mLayer->cellAt(columnItr); + if (!cell.isEmpty()) { + appendTileData(columnItr.x(), columnItr.y()); + } + + // Advance to the next column + ++columnItr.rx(); + --columnItr.ry(); + } + + // Advance to the next row + if (!shifted) { + ++rowItr.rx(); + startPos.rx() += mTileWidth / 2; + shifted = true; + } else { + ++rowItr.ry(); + startPos.rx() -= mTileWidth / 2; + shifted = false; } } @@ -322,7 +375,7 @@ QSGNode *TileLayerItem::updatePaintNode(QSGNode *node, if (mLayer->map()->orientation() == Map::Orthogonal) drawOrthogonalTileLayer(node, mapItem, mLayer, mVisibleTiles); else - IsometricRenderHelper(mRenderer, node, mapItem, mLayer, mVisibleTiles).addTilesToNode(); + IsometricRenderHelper(mRenderer, node, mapItem, mLayer, mapItem->visibleArea().toRect()).addTilesToNode(); return node; } @@ -330,13 +383,15 @@ QSGNode *TileLayerItem::updatePaintNode(QSGNode *node, void TileLayerItem::updateVisibleTiles() { const MapItem *mapItem = static_cast(parentItem()); - const QRect rect = mLayer->map()->orientation() == Map::Orthogonal - ? mapItem->visibleTileArea(mLayer) : mLayer->bounds(); - - if (mVisibleTiles != rect) { - mVisibleTiles = rect; + const QRect rect = mapItem->visibleTileArea(mLayer); + + // For isometric rendering, we need to use the visible screen rect, + // so the visibleTileArea optimisation doesn't work for us. + // If we don't do this, some tiles on the edge of the screen won't be rendered. + const bool shouldUpdate = mapItem->map()->orientation() == Map::Isometric || mVisibleTiles != rect; + mVisibleTiles = rect; + if (shouldUpdate) update(); - } } void TileLayerItem::layerVisibilityChanged()