Skip to content

Commit 9f2d7b0

Browse files
committed
tiledquickplugin: only render visible tiles
Fixes #2769
1 parent 0712c20 commit 9f2d7b0

File tree

2 files changed

+99
-48
lines changed

2 files changed

+99
-48
lines changed

src/tiledquick/qml/main.qml

+16-20
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,21 @@ ApplicationWindow {
1414
height: 720
1515
minimumWidth: 480
1616
minimumHeight: 320
17-
title: qsTr("Tiled Quick")
17+
title: qsTr("Tiled Quick | %1 | %2").arg(mapItem.visibleArea).arg(coordsText)
1818
visible: true
1919

20+
property string coordsText: {
21+
if (mapLoader.status === Tiled.MapLoader.Null) {
22+
return qsTr("No map file loaded")
23+
} else if (mapLoader.status === Tiled.MapLoader.Error) {
24+
return mapLoader.error
25+
} else {
26+
var mapRelativeCoords = singleFingerPanArea.mapToItem(mapItem, singleFingerPanArea.mouseX, singleFingerPanArea.mouseY)
27+
var tileCoords = mapItem.screenToTileCoords(mapRelativeCoords.x, mapRelativeCoords.y)
28+
return Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y)
29+
}
30+
}
31+
2032
FontLoader {
2133
id: fontAwesomeLoader
2234
source: "fonts/fontawesome.ttf"
@@ -116,9 +128,11 @@ ApplicationWindow {
116128
id: mapLoader
117129
}
118130

119-
Item {
131+
Rectangle {
120132
id: mapView
133+
color: "#aaff0000"
121134
anchors.fill: parent
135+
anchors.margins: 100
122136

123137
Item {
124138
id: mapContainer
@@ -190,22 +204,4 @@ ApplicationWindow {
190204
containerAnimation.start()
191205
}
192206
}
193-
194-
footer: Pane {
195-
RowLayout {
196-
Label {
197-
text: {
198-
if (mapLoader.status === Tiled.MapLoader.Null) {
199-
qsTr("No map file loaded")
200-
} else if (mapLoader.status === Tiled.MapLoader.Error) {
201-
mapLoader.error
202-
} else {
203-
var mapRelativeCoords = singleFingerPanArea.mapToItem(mapItem, singleFingerPanArea.mouseX, singleFingerPanArea.mouseY)
204-
var tileCoords = mapItem.screenToTileCoords(mapRelativeCoords.x, mapRelativeCoords.y)
205-
Math.floor(tileCoords.x) + ", " + Math.floor(tileCoords.y)
206-
}
207-
}
208-
}
209-
}
210-
}
211207
}

src/tiledquickplugin/tilelayeritem.cpp

+83-28
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,11 @@ class IsometricRenderHelper
185185
QSGNode *parent,
186186
const MapItem *mapItem,
187187
const TileLayer *layer,
188-
const QRect &rect) :
188+
const QRect &visibleScreenRect) :
189189
mRenderer(renderer),
190190
mParent(parent),
191191
mLayer(layer),
192-
mRect(rect),
192+
mVisibleScreenRect(visibleScreenRect),
193193
mTilesetHelper(mapItem),
194194
mTileWidth(mapItem->map()->tileWidth()),
195195
mTileHeight(mapItem->map()->tileHeight())
@@ -204,7 +204,7 @@ class IsometricRenderHelper
204204
Tiled::MapRenderer *mRenderer;
205205
QSGNode *mParent;
206206
const TileLayer *mLayer;
207-
const QRect mRect;
207+
const QRect mVisibleScreenRect;
208208
TilesetHelper mTilesetHelper;
209209
const int mTileWidth;
210210
const int mTileHeight;
@@ -251,33 +251,86 @@ void IsometricRenderHelper::appendTileData(int x, int y)
251251
mTileData.append(data);
252252
}
253253

254-
// TODO: make this function work with a subset of the entire layer rect
254+
// Mostly copied from IsometricRenderer::drawTileLayer().
255255
void IsometricRenderHelper::addTilesToNode()
256256
{
257-
if (mRect.isEmpty())
257+
if (mVisibleScreenRect.isEmpty())
258258
return;
259259

260-
mTileData.reserve(TilesNode::MaxTileCount);
261-
262-
for (int y = mRect.top(); y <= mRect.bottom(); ++y) {
263-
int _x = mRect.left();
264-
int _y = y;
260+
if (mTileWidth <= 0 || mTileHeight <= 1)
261+
return;
265262

266-
while (_x <= mRect.right() && _y >= mRect.top()) {
267-
appendTileData(_x, _y);
268-
++_x;
269-
--_y;
263+
QRect rect = mVisibleScreenRect;
264+
if (rect.isNull())
265+
rect = mRenderer->boundingRect(mLayer->bounds());
266+
267+
QMargins drawMargins = mLayer->drawMargins();
268+
drawMargins.setTop(drawMargins.top() - mTileHeight);
269+
drawMargins.setRight(drawMargins.right() - mTileWidth);
270+
271+
rect.adjust(-drawMargins.right(),
272+
-drawMargins.bottom(),
273+
drawMargins.left(),
274+
drawMargins.top());
275+
276+
// Determine the tile and pixel coordinates to start at
277+
QPointF tilePos = mRenderer->screenToTileCoords(rect.x(), rect.y());
278+
QPoint rowItr = QPoint(qFloor(tilePos.x()),
279+
qFloor(tilePos.y()));
280+
QPointF startPos = mRenderer->tileToScreenCoords(rowItr);
281+
startPos.rx() -= mTileWidth / 2;
282+
startPos.ry() += mTileHeight;
283+
284+
// Compensate for the layer position
285+
rowItr -= QPoint(mLayer->x(), mLayer->y());
286+
287+
/* Determine in which half of the tile the top-left corner of the area we
288+
* need to draw is. If we're in the upper half, we need to start one row
289+
* up due to those tiles being visible as well. How we go up one row
290+
* depends on whether we're in the left or right half of the tile.
291+
*/
292+
const bool inUpperHalf = startPos.y() - rect.y() > mTileHeight / 2;
293+
const bool inLeftHalf = rect.x() - startPos.x() < mTileWidth / 2;
294+
295+
if (inUpperHalf) {
296+
if (inLeftHalf) {
297+
--rowItr.rx();
298+
startPos.rx() -= mTileWidth / 2;
299+
} else {
300+
--rowItr.ry();
301+
startPos.rx() += mTileWidth / 2;
270302
}
303+
startPos.ry() -= mTileHeight / 2;
271304
}
272305

273-
for (int x = mRect.left() + 1; x <= mRect.right(); ++x) {
274-
int _x = x;
275-
int _y = mRect.bottom();
306+
// Determine whether the current row is shifted half a tile to the right
307+
bool shifted = inUpperHalf ^ inLeftHalf;
308+
309+
mTileData.reserve(TilesNode::MaxTileCount);
310+
311+
for (int y = static_cast<int>(startPos.y() * 2); y - mTileHeight * 2 < rect.bottom() * 2; y += mTileHeight) {
312+
QPoint columnItr = rowItr;
276313

277-
while (_x <= mRect.right() && _y >= mRect.top()) {
278-
appendTileData(_x, _y);
279-
++_x;
280-
--_y;
314+
for (int x = static_cast<int>(startPos.x()); x < rect.right(); x += mTileWidth) {
315+
const Cell &cell = mLayer->cellAt(columnItr);
316+
if (!cell.isEmpty()) {
317+
appendTileData(columnItr.x(), columnItr.y());
318+
}
319+
320+
// Advance to the next column
321+
++columnItr.rx();
322+
--columnItr.ry();
323+
}
324+
325+
// Advance to the next row
326+
if (!shifted) {
327+
++rowItr.rx();
328+
startPos.rx() += mTileWidth / 2;
329+
shifted = true;
330+
} else {
331+
++rowItr.ry();
332+
startPos.rx() -= mTileWidth / 2;
333+
shifted = false;
281334
}
282335
}
283336

@@ -322,21 +375,23 @@ QSGNode *TileLayerItem::updatePaintNode(QSGNode *node,
322375
if (mLayer->map()->orientation() == Map::Orthogonal)
323376
drawOrthogonalTileLayer(node, mapItem, mLayer, mVisibleTiles);
324377
else
325-
IsometricRenderHelper(mRenderer, node, mapItem, mLayer, mVisibleTiles).addTilesToNode();
378+
IsometricRenderHelper(mRenderer, node, mapItem, mLayer, mapItem->visibleArea().toRect()).addTilesToNode();
326379

327380
return node;
328381
}
329382

330383
void TileLayerItem::updateVisibleTiles()
331384
{
332385
const MapItem *mapItem = static_cast<MapItem*>(parentItem());
333-
const QRect rect = mLayer->map()->orientation() == Map::Orthogonal
334-
? mapItem->visibleTileArea(mLayer) : mLayer->bounds();
335-
336-
if (mVisibleTiles != rect) {
337-
mVisibleTiles = rect;
386+
const QRect rect = mapItem->visibleTileArea(mLayer);
387+
388+
// For isometric rendering, we need to use the visible screen rect,
389+
// so the visibleTileArea optimisation doesn't work for us.
390+
// If we don't do this, some tiles on the edge of the screen won't be rendered.
391+
const bool shouldUpdate = mapItem->map()->orientation() == Map::Isometric || mVisibleTiles != rect;
392+
mVisibleTiles = rect;
393+
if (shouldUpdate)
338394
update();
339-
}
340395
}
341396

342397
void TileLayerItem::layerVisibilityChanged()

0 commit comments

Comments
 (0)