@@ -185,11 +185,11 @@ class IsometricRenderHelper
185
185
QSGNode *parent,
186
186
const MapItem *mapItem,
187
187
const TileLayer *layer,
188
- const QRect &rect ) :
188
+ const QRect &visibleScreenRect ) :
189
189
mRenderer (renderer),
190
190
mParent (parent),
191
191
mLayer (layer),
192
- mRect (rect ),
192
+ mVisibleScreenRect (visibleScreenRect ),
193
193
mTilesetHelper (mapItem),
194
194
mTileWidth (mapItem->map ()->tileWidth()),
195
195
mTileHeight(mapItem->map ()->tileHeight())
@@ -204,7 +204,7 @@ class IsometricRenderHelper
204
204
Tiled::MapRenderer *mRenderer ;
205
205
QSGNode *mParent ;
206
206
const TileLayer *mLayer ;
207
- const QRect mRect ;
207
+ const QRect mVisibleScreenRect ;
208
208
TilesetHelper mTilesetHelper ;
209
209
const int mTileWidth ;
210
210
const int mTileHeight ;
@@ -251,33 +251,86 @@ void IsometricRenderHelper::appendTileData(int x, int y)
251
251
mTileData .append (data);
252
252
}
253
253
254
- // TODO: make this function work with a subset of the entire layer rect
254
+ // Mostly copied from IsometricRenderer::drawTileLayer().
255
255
void IsometricRenderHelper::addTilesToNode ()
256
256
{
257
- if (mRect .isEmpty ())
257
+ if (mVisibleScreenRect .isEmpty ())
258
258
return ;
259
259
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 ;
265
262
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 ;
270
302
}
303
+ startPos.ry () -= mTileHeight / 2 ;
271
304
}
272
305
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;
276
313
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 ;
281
334
}
282
335
}
283
336
@@ -322,21 +375,23 @@ QSGNode *TileLayerItem::updatePaintNode(QSGNode *node,
322
375
if (mLayer ->map ()->orientation () == Map::Orthogonal)
323
376
drawOrthogonalTileLayer (node, mapItem, mLayer , mVisibleTiles );
324
377
else
325
- IsometricRenderHelper (mRenderer , node, mapItem, mLayer , mVisibleTiles ).addTilesToNode ();
378
+ IsometricRenderHelper (mRenderer , node, mapItem, mLayer , mapItem-> visibleArea (). toRect () ).addTilesToNode ();
326
379
327
380
return node;
328
381
}
329
382
330
383
void TileLayerItem::updateVisibleTiles ()
331
384
{
332
385
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)
338
394
update ();
339
- }
340
395
}
341
396
342
397
void TileLayerItem::layerVisibilityChanged ()
0 commit comments