Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically Resize Maps - #260 #1651

Merged
merged 16 commits into from
Aug 15, 2017
Merged

Conversation

ketanhwr
Copy link
Contributor

mRegion keeps track of the non-empty region of layer. The bounds function is modified so that it calculates the bounds using mRegion itself.

@bjorn
Copy link
Member

bjorn commented Jul 14, 2017

I think this will not be good for performance. Hence I was suggesting, to keep track of a bounding QRect and only update it based on which chunks have been allocated. There is no need to keep track of the exact region nor do we need it to be accurate down to the tile.

@ketanhwr
Copy link
Contributor Author

Alright, so the region() function should be changed back to what it was prevously?

@ketanhwr
Copy link
Contributor Author

But why do you think that this won't be good for performance? In fact I think it's better now. Because earlier whenever the region() function was called, it traversed through all the cells but now it directly returns a QRegion and updates it when setCell is called.

@bjorn
Copy link
Member

bjorn commented Jul 14, 2017

But why do you think that this won't be good for performance? In fact I think it's better now. Because earlier whenever the region() function was called, it traversed through all the cells but now it directly returns a QRegion and updates it when setCell is called.

Yes, but when does the region function get called? I think this only happens for the tile layer used for the active brush. Maintaining the region for all tile layers of a map is largely a wasted effort, and it really isn't cheap to add/remove many 1x1 QRects to a QRegion (which is why the TileLayer::region(...) (now Chunk::region) function uses a special optimization to avoid too many operations on the QRegion).

@ketanhwr
Copy link
Contributor Author

So instead of maintaining a mRegion, you're suggesting that I should maintain a mBounds, right?

@bjorn
Copy link
Member

bjorn commented Jul 14, 2017

So instead of maintaining a mRegion, you're suggesting that I should maintain a mBounds, right?

Yes. In addition, I was suggesting that you update mBounds with chunk-granularity instead of tile-granularity.

Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm looking forward to test this. :-)

int x = std::min(0, bound.x());
int y = std::min(0, bound.y());
int width = std::max(mWidth, bound.width());
int height = std::max(mHeight, bound.height());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this? When a layer is empty, by all means its bounds should be empty as well. That is actually a nice optimization for the code using the bounds method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried using mBounds.boundintRect() previously, but that wasn't working for me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the must have been a problem elsewhere. Please try to take it out again and find out what's going wrong.

int width = std::max(mWidth, bound.width());
int height = std::max(mHeight, bound.height());

return QRect(x, y, width, height).translated(mX, mY);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since in your only usage of bounds so far, you're translating the rectangle back to local coordinates, I wonder if it may be better to just return local coordinates instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't get this one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was talking about the .translated(mX, mY) part. Because it's there, you're doing layer->bounds().translated(-(layer->x()), -(layer->y())) in the renderer. You could leave out both calls to translate for the same result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But for BrushItem it draws the selection on the basis of x() and y().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if both the translate are removed, then BrushItem won't work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see TileLayer::bounds being used by BrushItem. If you do use it there and it wants the bounds to be translated, then yes you should either leave this in there or add a translation in BrushItem.

@@ -513,6 +515,7 @@ class TILEDSHARED_EXPORT TileLayer : public Layer
int mHeight;
Cell mEmptyCell;
QHash<QPoint, Chunk> mChunks;
QRegion mBounds;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we only care about the bounding rectangle, why is this a QRegion instead of a QRect? I don't currently see a use-case for using the region.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I previously tried with QRect, but we cannot do arithmetic operations on QRect. Although we can convert QRect to QRegion, then add a chunk and then use QRegion::boundingRect but I guess that would have the same complexity.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only need to extend the rectangle in some cases. It's easy to do, but then, Qt even has QRect::united. Not going through QRegion will be a lot more efficient.

mBounds = mBounds.united(QRect(x - (x & CHUNK_MASK),
y - (y & CHUNK_MASK),
CHUNK_SIZE,
CHUNK_SIZE));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the line in the else is multiple lines long please use {} around it. And since the else then has it, the if-part also should have it

int x = std::min(0, mBounds.x());
int y = std::min(0, mBounds.y());
// int width = std::max(mWidth, mBounds.width());
// int height = std::max(mHeight, mBounds.height());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you want to remove those?

@Ablu
Copy link
Contributor

Ablu commented Jul 17, 2017

you broke a test apparently... Due to this the travis test failed.

@@ -400,6 +410,7 @@ void TileLayer::rotate(RotateDirection direction)
mWidth = newWidth;
mHeight = newHeight;
mChunks = newLayer->mChunks;
updateBounds();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not mBounds = newLayer->mBounds;? (and of course, passing mX and mY to constructor when creating newLayer. This goes for all these functions creating a new layer.

int x = std::min(0, mBounds.x());
int y = std::min(0, mBounds.y());
int width = std::max(mWidth, mBounds.width());
int height = std::max(mHeight, mBounds.height());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this and document where it is causing issues, so that we can find a way to fix that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QRegion TilePainter::paintableRegion(const QRegion &region) const
{
    const QRegion bounds = QRegion(mTileLayer->bounds());
    QRegion intersection = bounds.intersected(region);

    const QRegion &selection = mMapDocument->selectedArea();
    if (!selection.isEmpty())
        intersection &= selection;

    return intersection;
}

Due to this, if we directly return mBounds then we won't be able to paint the tile layer.

int startY = 0;
int endX = layer->width() - 1;
int endY = layer->height() - 1;
QRect bounds = layer->bounds().translated(-(layer->x()), -(layer->y()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be written shorter as .translated(-layer->position())

Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting to look pretty good.

@@ -254,7 +254,7 @@ void HexagonalRenderer::drawTileLayer(QPainter *painter,
QRect rect = exposed.toAlignedRect();

if (rect.isNull())
rect = boundingRect(layer->bounds());
rect = boundingRect(layer->rect());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be bounds, because there is no point in trying to draw anything outside of it.

@@ -191,7 +191,7 @@ void IsometricRenderer::drawTileLayer(QPainter *painter,

QRect rect = exposed.toAlignedRect();
if (rect.isNull())
rect = boundingRect(layer->bounds());
rect = boundingRect(layer->rect());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be bounds, again because outside of that there are never any tiles to draw (also we need to use bounds because when tiles were placed on an infinite map, we want to make sure to draw all of them).

@@ -640,7 +640,7 @@ Layer *TileLayer::mergedWith(Layer *other) const
Q_ASSERT(canMergeWith(other));

const TileLayer *o = static_cast<TileLayer*>(other);
const QRect unitedBounds = bounds().united(o->bounds());
const QRect unitedBounds = rect().united(o->rect());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid confusion, this should be unitedRect.

if (!tileLayer->rect().intersects(QRect(preview->x(),
preview->y(),
preview->width(),
preview->height())))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I wonder why this wasn't using preview->bounds() before. In any case, it can be changed to:

if (!tileLayer->rect().intersects(preview->bounds()))

@@ -349,7 +349,9 @@ class TILEDSHARED_EXPORT TileLayer : public Layer
/**
* Returns the bounds of this layer.
*/
QRect bounds() const { return QRect(mX, mY, mWidth, mHeight); }
QRect bounds() const { return mBounds.translated(mX, mY); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested to use bounds in the map renderers, but due to an assert this will currently only work if this function is implemented as:

QRect bounds() const { return mBounds.translated(mX, mY).intersected(rect()); }

That is because mBounds may extend beyond the limits imposed by the layer size due to growing it chunk-by-chunk. I think that is a fine implementation for now, and the intersection can be taken out again when we actually allow layers to grow (and take out the assert in cellAt).

@ketanhwr ketanhwr changed the title Modifies bounds function Automatically Resize Maps - #260 Jul 18, 2017
@ketanhwr
Copy link
Contributor Author

I'm not able to understand why the build fails 😕

Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments. I'm sorry it's not exhaustive.

for (int y = 0; y < tileLayer->height(); ++y) {
for (int x = 0; x < tileLayer->width(); ++x) {
if (x > 0)
for (int y = startY; y <= endY; ++y) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you just use bounds.left() and bounds.right() here, then the above can be written much shorter:

QRect bounds = map->infinite() ? tileLayer->bounds() : tileLayer->rect();
bounds.translate(-layer->position());

I do wonder a little what somebody would do with multiple CSV files that cover various areas of different tile layers, especially with no way of knowing how to map them back relative to each other, but that's the way it is when exporting infinite maps in this format...

const QRegion bounds = QRegion(mTileLayer->rect());
QRegion intersection;

if (mTileLayer->map()->infinite())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just in case, please obtain the map from the mMapDocument, since tile layers are not guaranteed to have a map but the MapDocument is.

if (mTileLayer->map()->infinite())
intersection = region;
else
intersection = bounds.intersected(region);;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole thing can be written a lot shorter:

QRegion intersection = region;
if (!mMapDocument->map()->infinite())
    intersection &= QRegion(mTileLayer->rect());

@@ -71,6 +71,8 @@ class TILEDSHARED_EXPORT HexagonalRenderer : public OrthogonalRenderer

QSize mapSize() const override;

QPoint mapStart() const override;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider replacing mapSize and mapStart with a single QRect mapBoundingRect() const function.

int startX = bounds.left();
int startY = bounds.top();
int endX = bounds.right();
int endY = bounds.bottom();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should still have the -1:

int endX = bounds.right() - 1;
int endY = bounds.bottom() - 1;

Because the right and bottom of a QRect are inclusive.

Copy link
Contributor Author

@ketanhwr ketanhwr Jul 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was previously iterating upto layer->width() - 1. So if - 1 is added, then it doesn't render the last row/column.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, precisely because QRect is inclusive, we should indeed not do -1.

mDarkRectangle->setRect(sceneRect);

if (mMapDocument->map()->infinite())
mDarkRectangle->setRect(QRect());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to find some way to still darken the view, for the "Highlight Current Layer" feature to work on infinite maps.

<item row="3" column="1">
<widget class="QCheckBox" name="mapInfinite">
<property name="text">
<string>Automatically Resize Map</string>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see if this checkbox fits in the "Map Size" box, and disable the width/height inputs and hide the pixel size display for infinite maps (I think the map size should just be 0,0).


if (!tileLayer->map()->infinite())
captured &= QRect(tileLayer->x(), tileLayer->y(),
tileLayer->width(), tileLayer->height());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this intersection at all?

@ketanhwr ketanhwr force-pushed the infinite-maps branch 2 times, most recently from a6f6c51 to 8965443 Compare July 30, 2017 09:13
Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While there is indeed the problem with the scene rect, and I have no good solution for this now, I've found a lot of small issues with the existing patch in the meantime which can be addressed.

I suggest we work towards merging this patch without trying to solve the "jumping" problem for now. It will probably take some trial and error to find a workable solution to that, but it's more important to get all the other parts of the code adjusted in the right way.

@@ -129,6 +129,9 @@ class MapReaderPrivate
bool mReadingExternalTileset;

QXmlStreamReader xml;

int startX;
int startY;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming style: should be mStartX and mStartY.

However, I think you should anyway just pass these around as function parameters rather than having them as members.

@@ -70,10 +70,7 @@ class TILEDSHARED_EXPORT MapRenderer
*/
const Map *map() const;

/**
* Returns the size in pixels of the map associated with this renderer.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave an updated comment in place.

tileLayerVariant[QLatin1String("width")] = tileLayer.width();
tileLayerVariant[QLatin1String("height")] = tileLayer.height();
tileLayerVariant[QLatin1String("startx")] = 0;
tileLayerVariant[QLatin1String("starty")] = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please just leave out these values for finite maps.

@@ -48,6 +48,8 @@
#include <QDir>
#include <QXmlStreamWriter>

#include <QDebug>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember to remove this include again.

w.writeAttribute(QLatin1String("startx"),
QString::number(bounds.left()));
w.writeAttribute(QLatin1String("starty"),
QString::number(bounds.top()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too, please don't write those attributes for finite maps.

@@ -98,7 +98,7 @@ static QRectF cellRect(const MapRenderer &renderer,
static QRect computeMapRect(const MapRenderer &renderer)
{
// Start with the basic map size
QRectF rect(QPointF(0, 0), renderer.mapSize());
QRectF rect(QPointF(0, 0), renderer.mapBoundingRect().size());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should just be initialized to renderer.mapBoundingRect(), not just its size.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How exactly do I test the Thumbnail Renderer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thumbnail renderer renders the tiles for the tile stamp dock. So you can simply add some tiles there to test it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ThumbnailRenderer should really be unified with MiniMapRenderer, but that's something for another time...

@@ -197,12 +199,26 @@ static QRegion fillRegion(const TileLayer *layer, QPoint fillOrigin,
if (!layer->contains(fillOrigin))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check should be disabled for infinite maps (once contains is back to its original form).

const int layerHeight = layer->height();
QRect bounds = layer->bounds().translated(-layer->position());
if (!layer->map()->infinite())
bounds = layer->rect();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Translated by -layer->position() as well, right?

@@ -101,7 +101,7 @@ int TmxRasterizer::render(const QString &mapFileName,
break;
}

QSize mapSize = renderer->mapSize();
QSize mapSize = renderer->mapBoundingRect().size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need to store the bounding rect and translate the painter based on the topLeft of it.

@@ -53,10 +53,10 @@ void test_StaggeredRenderer::mapSize()
StaggeredRenderer renderer(mMap);

TileLayer *tileLayer = static_cast<TileLayer*>(mMap->layerAt(0));
QSize mapSize = renderer.mapSize();
QSize mapSize = renderer.mapBoundingRect().size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the test a little more complete, just take the bounding rect and compare it to a QRect(0, 0, 10 * 64 + 32, 10 * 16 + 16).

@Ablu
Copy link
Contributor

Ablu commented Aug 2, 2017

Travis seems to have a compiling issue:

test_staggeredrenderer.cpp:56:11: error: no viable conversion from 'QRect' to
      'QSize'
    QSize mapBoundingRect = renderer.mapBoundingRect();
          ^                 ~~~~~~~~~~~~~~~~~~~~~~~~~~

map()->width() * tileWidth + 1);
const int endY = qMin(qCeil(rect.bottom()),
map()->height() * tileHeight + 1);
int startX = ((int) (rect.x() / tileWidth - 1)) * tileWidth;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the -1 is to make it work in case of negative coordinates, but it means an extra column of tiles will be rendered in positive coordinate space. A real fix would be to use qFloor(rect.x() / tileWidth) * tileWidth.

int endY = qCeil(rect.bottom());

if (!map()->infinite()) {
startX = qMax(0, (int) (rect.x() / tileWidth) * tileWidth);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you should reuse the value of startX:

startX = qMax(0, startX);


QCOMPARE(mapSize, QSize(10 * 64 + 32, 10 * 16 + 16));
QCOMPARE(renderer.boundingRect(tileLayer->bounds()),
QRect(QPoint(), mapSize));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you removing the test of StaggeredRenderer::boundingRect? It should be possible to just change it to:

QCOMPARE(renderer.boundingRect(tileLayer->rect()), mapBoundingRect);

Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some review feedback.

I guess the main things still open for this change would be:

  • Checking the behavior of automapping. The main thing to fix is AutomappingManager::autoMap taking the map size rather than calculating the combined bounds, but there may be other parts to modify.

  • Implementing the alternative chunk-based storage format.

@@ -204,7 +204,7 @@ void TerrainBrush::capture()

const QPoint position = tilePosition() - tileLayer->position();

if (!tileLayer->contains(position))
if (!tileLayer->contains(position) && !mapDocument()->map()->infinite())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is no longer necessary. I think capturing outside of the map can simply capture "no terrain", also for finite maps.

@@ -373,7 +373,7 @@ void TerrainBrush::updateBrush(QPoint cursorPos, const QVector<QPoint> *list)
}

// if the cursor is outside of the map, bail out
if (!currentLayer->contains(cursorPos)) {
if (!currentLayer->contains(cursorPos) && !mapDocument()->map()->infinite()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contains check should not be needed anymore even for finite maps.

@@ -395,7 +395,7 @@ void TerrainBrush::updateBrush(QPoint cursorPos, const QVector<QPoint> *list)
transitionList.reserve(list->size());
for (QPoint p : *list) {
p -= layerPosition;
if (currentLayer->contains(p))
if (currentLayer->contains(p) || mapDocument()->map()->infinite())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Contains check should not be needed anymore even for finite maps.

@@ -68,7 +70,7 @@ Cell TilePainter::cellAt(int x, int y) const
const int layerX = x - mTileLayer->x();
const int layerY = y - mTileLayer->y();

if (!mTileLayer->contains(layerX, layerY))
if (!mTileLayer->contains(layerX, layerY) && !mMapDocument->map()->infinite())
Copy link
Member

@bjorn bjorn Aug 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check is not necessary at all anymore. If the layer does not contain this position, it will anyway return an empty cell.

Edit: GitHub seems to match this comment to a different line now. In this function it is of course still needed..

if (!layer->contains(fillOrigin) && !layer->map()->infinite())
return fillRegion;

if (layer->map()->infinite() && !layer->bounds().contains(fillOrigin))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please combine the above checks with getting the bounds below:

QRect bounds = layer->map()->infinite() ? layer->bounds() : layer->rect();
if (!bounds.contains(fillOrigin))
    return fillRegion;
bounds.translate(-layer->position());

@@ -101,7 +101,8 @@ int TmxRasterizer::render(const QString &mapFileName,
break;
}

QSize mapSize = renderer->mapSize();
QSize mapSize = renderer->mapBoundingRect().size();
QPoint mapOffset = renderer->mapBoundingRect().topLeft();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't call mapBoundingRect twice.

Copy link
Member

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll still need to adjust HexagonalRenderer::mapBoundingRect.

@@ -338,14 +342,14 @@ void HexagonalRenderer::drawTileLayer(QPainter *painter,
if (p.doStaggerY(startTile.y() + layer->y()))
startPos.rx() -= p.columnWidth;

for (; startPos.y() < rect.bottom() && startTile.y() < layer->height(); startTile.ry()++) {
for (; startPos.y() < rect.bottom() && (startTile.y() < layer->height() || map()->infinite()); startTile.ry()++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please still optimize this to use an endY that is either layer->height() or layer->bounds(), same for X.

@@ -242,7 +268,7 @@ void IsometricRenderer::drawTileLayer(QPainter *painter,
QPoint columnItr = rowItr;

for (int x = startPos.x(); x < rect.right(); x += tileWidth) {
if (layer->contains(columnItr)) {
if (map()->infinite() || layer->contains(columnItr)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can drop both these checks and rely only on !cell.isEmpty() below.

@@ -289,6 +318,9 @@ void HexagonalRenderer::drawTileLayer(QPainter *painter,

CellRenderer renderer(painter, CellRenderer::HexagonalCells);

const int endX = map()->infinite() ? layer->bounds().width() : layer->width();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the endX should be layer->bounds().right() - layer->x() + 1 in case of infinite maps. Similar for Y.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But not for layer->width() ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about layer->width()? My point is that endX should be the right-most X coordinate (+1 because it's one beyond that), like it is for finite maps. But you just took bounds().width(), which does not take into account that bounds().x() isn't always 0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so instead of layer->x(), it should be layer->bounds().x(), right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the - layer->x() part is to change the bounds to local coordinates, since the bounds() include the layer's position. Subtracting layer->bounds().x() would defeat the point of using layer->bounds().right().

QPoint rowTile = startTile;
QPoint rowPos = startPos;

for (; rowPos.x() < rect.right() && (rowTile.x() < layer->width() || map()->infinite()); rowTile.rx() += 2) {
for (; rowPos.x() < rect.right() && endX; rowTile.rx() += 2) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ 🤦‍♂️ 🤦‍♂️

// The map size is the same regardless of which indexes are shifted.
if (p.staggerX) {
QSize size(map()->width() * p.columnWidth + p.sideOffsetX,
map()->height() * (p.tileHeight + p.sideLengthY));
if (!map()->infinite()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider that infinite and finite maps are not so different that you couldn't use the same code for both, just using the bounds:

QRect mapBounds;

if (map()->inifinite()) {
    // unite with the layer bounds
} else {
    mapBounds = QRect(0, 0, map()->width(), map()->height());
}

// Calculate bounding rect based on bounds (no need for checking infinite anymore)

map()->height() * (p.tileHeight + p.sideLengthY));

if (map()->width() > 1)
size.rheight() += p.rowHeight;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this line is also needed for infinite maps. rowHeight needs to be added because of the staggering. Same for columnWidth below.

}

if (mapBounds.size() == QSize(0, 0))
mapBounds.setSize(QSize(1, 1));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this before. If the size is set to (0, 0) then after creating a new map, the 'weird' scrolling problem starts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we work around that problem in the MapScene? It's not related to the renderers.

@@ -339,14 +365,14 @@ void HexagonalRenderer::drawTileLayer(QPainter *painter,
if (p.doStaggerY(startTile.y() + layer->y()))
startPos.rx() -= p.columnWidth;

for (; startPos.y() < rect.bottom() && startTile.y() < layer->height(); startTile.ry()++) {
for (; startPos.y() < rect.bottom() && endY; startTile.ry()++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix all cases.

@bjorn bjorn merged commit 59b3747 into mapeditor:master Aug 15, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants