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

Automatically Resize Maps - #260 #1651

merged 16 commits into from Aug 15, 2017

Conversation

@ketanhwr
Copy link
Contributor

@ketanhwr ketanhwr commented Jul 14, 2017

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
Owner

@bjorn 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

@ketanhwr ketanhwr commented Jul 14, 2017

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

@ketanhwr
Copy link
Contributor Author

@ketanhwr ketanhwr 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.

@bjorn
Copy link
Owner

@bjorn 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

@ketanhwr ketanhwr commented Jul 14, 2017

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

@bjorn
Copy link
Owner

@bjorn 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
Owner

@bjorn bjorn left a comment

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());

This comment has been minimized.

@bjorn

bjorn Jul 17, 2017
Owner

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.

This comment has been minimized.

@ketanhwr

ketanhwr Jul 17, 2017
Author Contributor

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

This comment has been minimized.

@bjorn

bjorn Jul 17, 2017
Owner

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);

This comment has been minimized.

@bjorn

bjorn Jul 17, 2017
Owner

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?

This comment has been minimized.

@ketanhwr

ketanhwr Jul 17, 2017
Author Contributor

I didn't get this one?

This comment has been minimized.

@bjorn

bjorn Jul 17, 2017
Owner

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.

This comment has been minimized.

@ketanhwr

ketanhwr Jul 17, 2017
Author Contributor

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

This comment has been minimized.

@ketanhwr

ketanhwr Jul 17, 2017
Author Contributor

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

This comment has been minimized.

@bjorn

bjorn Jul 17, 2017
Owner

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;

This comment has been minimized.

@bjorn

bjorn Jul 17, 2017
Owner

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.

This comment has been minimized.

@ketanhwr

ketanhwr Jul 17, 2017
Author Contributor

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.

This comment has been minimized.

@bjorn

bjorn Jul 17, 2017
Owner

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));

This comment has been minimized.

@Ablu

Ablu Jul 17, 2017
Contributor

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());

This comment has been minimized.

@Ablu

Ablu Jul 17, 2017
Contributor

I guess you want to remove those?

@Ablu
Copy link
Contributor

@Ablu 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();

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

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());

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

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

This comment has been minimized.

@ketanhwr

ketanhwr Jul 18, 2017
Author Contributor

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()));

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

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

Copy link
Owner

@bjorn bjorn left a comment

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());

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

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());

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

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());

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

To avoid confusion, this should be unitedRect.

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

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

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); }

This comment has been minimized.

@bjorn

bjorn Jul 18, 2017
Owner

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

@ketanhwr ketanhwr commented Jul 18, 2017

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

Copy link
Owner

@bjorn bjorn left a comment

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) {

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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())

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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);;

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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;

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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();

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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.

This comment has been minimized.

@ketanhwr

ketanhwr Jul 25, 2017
Author Contributor

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

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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

mDarkRectangle->setRect(sceneRect);

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

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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>

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

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());

This comment has been minimized.

@bjorn

bjorn Jul 25, 2017
Owner

Do we need this intersection at all?

@ketanhwr ketanhwr force-pushed the ketanhwr:infinite-maps branch from 3f5d6c3 to 26076ee Jul 28, 2017
@ketanhwr ketanhwr force-pushed the ketanhwr:infinite-maps branch from 6bda72e to 11cd3b5 Jul 28, 2017
@ketanhwr ketanhwr force-pushed the ketanhwr:infinite-maps branch 2 times, most recently from a6f6c51 to 8965443 Jul 30, 2017
@ketanhwr ketanhwr force-pushed the ketanhwr:infinite-maps branch from 8965443 to 4136e44 Jul 31, 2017
Copy link
Owner

@bjorn bjorn left a comment

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;

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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.
*/

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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;

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

Please just leave out these values for finite maps.

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

#include <QDebug>

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

Remember to remove this include again.

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

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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());

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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

This comment has been minimized.

@ketanhwr

ketanhwr Aug 1, 2017
Author Contributor

How exactly do I test the Thumbnail Renderer?

This comment has been minimized.

@Ablu

Ablu Aug 2, 2017
Contributor

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

This comment has been minimized.

@bjorn

bjorn Aug 2, 2017
Owner

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))

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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();

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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();

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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();

This comment has been minimized.

@bjorn

bjorn Jul 31, 2017
Owner

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 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;

This comment has been minimized.

@bjorn

bjorn Aug 2, 2017
Owner

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);

This comment has been minimized.

@bjorn

bjorn Aug 2, 2017
Owner

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));

This comment has been minimized.

@bjorn

bjorn Aug 2, 2017
Owner

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
Owner

@bjorn bjorn left a comment

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())

This comment has been minimized.

@bjorn

bjorn Aug 6, 2017
Owner

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()) {

This comment has been minimized.

@bjorn

bjorn Aug 6, 2017
Owner

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())

This comment has been minimized.

@bjorn

bjorn Aug 6, 2017
Owner

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())

This comment has been minimized.

@bjorn

bjorn Aug 6, 2017
Owner

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))

This comment has been minimized.

@bjorn

bjorn Aug 6, 2017
Owner

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();

This comment has been minimized.

@bjorn

bjorn Aug 6, 2017
Owner

Please don't call mapBoundingRect twice.

ketanhwr added 3 commits Aug 7, 2017
Copy link
Owner

@bjorn bjorn left a comment

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()++) {

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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)) {

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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();

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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

This comment has been minimized.

@ketanhwr

ketanhwr Aug 15, 2017
Author Contributor

But not for layer->width() ?

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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.

This comment has been minimized.

@ketanhwr

ketanhwr Aug 15, 2017
Author Contributor

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

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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) {

This comment has been minimized.

This comment has been minimized.

@ketanhwr

ketanhwr Aug 15, 2017
Author Contributor

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

// 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()) {

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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;

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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));

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

Why is this?

This comment has been minimized.

@ketanhwr

ketanhwr Aug 15, 2017
Author Contributor

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

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

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()++) {

This comment has been minimized.

@bjorn

bjorn Aug 15, 2017
Owner

Please fix all cases.

ketanhwr added 2 commits Aug 15, 2017
@bjorn bjorn merged commit 59b3747 into bjorn:master Aug 15, 2017
1 of 2 checks passed
1 of 2 checks passed
continuous-integration/appveyor/pr Waiting for AppVeyor build to complete
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

3 participants
You can’t perform that action at this time.