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
24 changes: 19 additions & 5 deletions src/libtiled/gidmapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,24 @@ QByteArray GidMapper::encodeLayerData(const TileLayer &tileLayer,
Q_ASSERT(format != Map::XML);
Q_ASSERT(format != Map::CSV);

int startX = 0;
int startY = 0;
int endX = tileLayer.width() - 1;
int endY = tileLayer.height() - 1;

if (tileLayer.map()->infinite()) {
QRect bounds = tileLayer.bounds().translated(-tileLayer.position());
startX = bounds.left();
startY = bounds.top();
endX = bounds.right();
endY = bounds.bottom();
}

QByteArray tileData;
tileData.reserve(tileLayer.height() * tileLayer.width() * 4);
tileData.reserve((endX - startX + 1) * (endY - startY + 1) * 4);

for (int y = 0; y < tileLayer.height(); ++y) {
for (int x = 0; x < tileLayer.width(); ++x) {
for (int y = startY; y <= endY; ++y) {
for (int x = startX; x <= endX; ++x) {
const unsigned gid = cellToGid(tileLayer.cellAt(x, y));
tileData.append((char) (gid));
tileData.append((char) (gid >> 8));
Expand All @@ -175,7 +188,8 @@ QByteArray GidMapper::encodeLayerData(const TileLayer &tileLayer,

GidMapper::DecodeError GidMapper::decodeLayerData(TileLayer &tileLayer,
const QByteArray &layerData,
Map::LayerDataFormat format) const
Map::LayerDataFormat format,
int startX, int startY) const
{
Q_ASSERT(format != Map::XML);
Q_ASSERT(format != Map::CSV);
Expand Down Expand Up @@ -206,7 +220,7 @@ GidMapper::DecodeError GidMapper::decodeLayerData(TileLayer &tileLayer,
return isEmpty() ? TileButNoTilesets : InvalidTile;
}

tileLayer.setCell(x, y, result);
tileLayer.setCell(x + startX, y + startY, result);

x++;
if (x == tileLayer.width()) {
Expand Down
3 changes: 2 additions & 1 deletion src/libtiled/gidmapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ class TILEDSHARED_EXPORT GidMapper

DecodeError decodeLayerData(TileLayer &tileLayer,
const QByteArray &layerData,
Map::LayerDataFormat format) const;
Map::LayerDataFormat format,
int startX, int startY) const;

unsigned invalidTile() const;

Expand Down
53 changes: 28 additions & 25 deletions src/libtiled/hexagonalrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ HexagonalRenderer::RenderParams::RenderParams(const Map *map)
rowHeight = sideOffsetY + sideLengthY;
}


QSize HexagonalRenderer::mapSize() const
QRect HexagonalRenderer::mapBoundingRect() const
{
const RenderParams p(map());

Expand All @@ -76,15 +75,15 @@ QSize HexagonalRenderer::mapSize() const
if (map()->width() > 1)
size.rheight() += p.rowHeight;

return size;
return QRect(0, 0, size.width(), size.height());
} else {
QSize size(map()->width() * (p.tileWidth + p.sideLengthX),
map()->height() * p.rowHeight + p.sideOffsetY);

if (map()->height() > 1)
size.rwidth() += p.columnWidth;

return size;
return QRect(0, 0, size.width(), size.height());
}
}

Expand Down Expand Up @@ -144,8 +143,10 @@ void HexagonalRenderer::drawGrid(QPainter *painter, const QRectF &exposed,
if (inLeftHalf)
startTile.rx()--;

startTile.setX(qMax(0, startTile.x()));
startTile.setY(qMax(0, startTile.y()));
if (!map()->infinite()) {
startTile.setX(qMax(0, startTile.x()));
startTile.setY(qMax(0, startTile.y()));
}

startPos = tileToScreenCoords(startTile).toPoint();

Expand All @@ -171,14 +172,14 @@ void HexagonalRenderer::drawGrid(QPainter *painter, const QRectF &exposed,
if (p.doStaggerX(startTile.x()))
startPos.ry() -= p.rowHeight;

for (; startPos.x() <= rect.right() && startTile.x() < map()->width(); startTile.rx()++) {
for (; startPos.x() <= rect.right() && (startTile.x() < map()->width() || map()->infinite()); startTile.rx()++) {
QPoint rowTile = startTile;
QPoint rowPos = startPos;

if (p.doStaggerX(startTile.x()))
rowPos.ry() += p.rowHeight;

for (; rowPos.y() <= rect.bottom() && rowTile.y() < map()->height(); rowTile.ry()++) {
for (; rowPos.y() <= rect.bottom() && (rowTile.y() < map()->height() || map()->infinite()); rowTile.ry()++) {
lines.append(QLine(rowPos + oct[1], rowPos + oct[2]));
lines.append(QLine(rowPos + oct[2], rowPos + oct[3]));
lines.append(QLine(rowPos + oct[3], rowPos + oct[4]));
Expand Down Expand Up @@ -209,14 +210,14 @@ void HexagonalRenderer::drawGrid(QPainter *painter, const QRectF &exposed,
if (p.doStaggerY(startTile.y()))
startPos.rx() -= p.columnWidth;

for (; startPos.y() <= rect.bottom() && startTile.y() < map()->height(); startTile.ry()++) {
for (; startPos.y() <= rect.bottom() && (startTile.y() < map()->height() || map()->infinite()); startTile.ry()++) {
QPoint rowTile = startTile;
QPoint rowPos = startPos;

if (p.doStaggerY(startTile.y()))
rowPos.rx() += p.columnWidth;

for (; rowPos.x() <= rect.right() && rowTile.x() < map()->width(); rowTile.rx()++) {
for (; rowPos.x() <= rect.right() && (rowTile.x() < map()->width() || map()->infinite()); rowTile.rx()++) {
lines.append(QLine(rowPos + oct[0], rowPos + oct[1]));
lines.append(QLine(rowPos + oct[1], rowPos + oct[2]));
lines.append(QLine(rowPos + oct[3], rowPos + oct[4]));
Expand Down Expand Up @@ -289,27 +290,27 @@ void HexagonalRenderer::drawTileLayer(QPainter *painter,
CellRenderer renderer(painter, CellRenderer::HexagonalCells);

if (p.staggerX) {
startTile.setX(qMax(-1, startTile.x()));
startTile.setY(qMax(-1, startTile.y()));
if (!map()->infinite()) {
startTile.setX(qMax(-1, startTile.x()));
startTile.setY(qMax(-1, startTile.y()));
}

startPos = tileToScreenCoords(startTile + layer->position()).toPoint();
startPos.ry() += p.tileHeight;

bool staggeredRow = p.doStaggerX(startTile.x() + layer->x());

for (; startPos.y() < rect.bottom() && startTile.y() < layer->height();) {
for (; startPos.y() < rect.bottom() && (startTile.y() < layer->height() || map()->infinite());) {
QPoint rowTile = startTile;
QPoint rowPos = startPos;

for (; rowPos.x() < rect.right() && rowTile.x() < layer->width(); rowTile.rx() += 2) {
if (layer->contains(rowTile)) {
const Cell &cell = layer->cellAt(rowTile);
for (; rowPos.x() < rect.right() && (rowTile.x() < layer->width() || map()->infinite()); rowTile.rx() += 2) {
const Cell &cell = layer->cellAt(rowTile);

if (!cell.isEmpty()) {
Tile *tile = cell.tile();
QSize size = tile ? tile->size() : map()->tileSize();
renderer.render(cell, rowPos, size, CellRenderer::BottomLeft);
}
if (!cell.isEmpty()) {
Tile *tile = cell.tile();
QSize size = tile ? tile->size() : map()->tileSize();
renderer.render(cell, rowPos, size, CellRenderer::BottomLeft);
}

rowPos.rx() += p.tileWidth + p.sideLengthX;
Expand All @@ -329,8 +330,10 @@ void HexagonalRenderer::drawTileLayer(QPainter *painter,
startPos.ry() += p.rowHeight;
}
} else {
startTile.setX(qMax(0, startTile.x()));
startTile.setY(qMax(0, startTile.y()));
if (!map()->infinite()) {
startTile.setX(qMax(0, startTile.x()));
startTile.setY(qMax(0, startTile.y()));
}

startPos = tileToScreenCoords(startTile + layer->position()).toPoint();
startPos.ry() += p.tileHeight;
Expand All @@ -339,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.

QPoint rowTile = startTile;
QPoint rowPos = startPos;

if (p.doStaggerY(startTile.y() + layer->y()))
rowPos.rx() += p.columnWidth;

for (; rowPos.x() < rect.right() && rowTile.x() < layer->width(); rowTile.rx()++) {
for (; rowPos.x() < rect.right() && (rowTile.x() < layer->width() || map()->infinite()); rowTile.rx()++) {
const Cell &cell = layer->cellAt(rowTile);

if (!cell.isEmpty()) {
Expand Down
2 changes: 1 addition & 1 deletion src/libtiled/hexagonalrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class TILEDSHARED_EXPORT HexagonalRenderer : public OrthogonalRenderer
public:
HexagonalRenderer(const Map *map) : OrthogonalRenderer(map) {}

QSize mapSize() const override;
QRect mapBoundingRect() const override;

QRect boundingRect(const QRect &rect) const override;

Expand Down
47 changes: 36 additions & 11 deletions src/libtiled/isometricrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,31 @@

using namespace Tiled;

QSize IsometricRenderer::mapSize() const
QRect IsometricRenderer::mapBoundingRect() const
{
// Map width and height contribute equally in both directions
const int side = map()->height() + map()->width();
return QSize(side * map()->tileWidth() / 2,
if (!map()->infinite()) {
const int side = map()->height() + map()->width();
return QRect(0, 0, side * map()->tileWidth() / 2,
side * map()->tileHeight() / 2);
}

QRect mapBounds;

LayerIterator iterator(map());
while (Layer *layer = iterator.next()) {
if (TileLayer *tileLayer = dynamic_cast<TileLayer*>(layer))
mapBounds = mapBounds.united(tileLayer->bounds());
}

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

const int origin = mapBounds.x() + mapBounds.y();
const int side = mapBounds.width() + mapBounds.height();

return QRect(origin * map()->tileWidth() / 2,
origin * map()->tileHeight() / 2,
side * map()->tileWidth() / 2,
side * map()->tileHeight() / 2);
}

Expand Down Expand Up @@ -157,12 +177,17 @@ void IsometricRenderer::drawGrid(QPainter *painter, const QRectF &rect,
r.adjust(-tileWidth / 2, -tileHeight / 2,
tileWidth / 2, tileHeight / 2);

const int startX = qMax(qreal(0), screenToTileCoords(r.topLeft()).x());
const int startY = qMax(qreal(0), screenToTileCoords(r.topRight()).y());
const int endX = qMin(qreal(map()->width()),
screenToTileCoords(r.bottomRight()).x());
const int endY = qMin(qreal(map()->height()),
screenToTileCoords(r.bottomLeft()).y());
int startX = screenToTileCoords(r.topLeft()).x();
int startY = screenToTileCoords(r.topRight()).y();
int endX = screenToTileCoords(r.bottomRight()).x();
int endY = screenToTileCoords(r.bottomLeft()).y();

if (!map()->infinite()) {
startX = qMax(qreal(0), qreal(startX));
startY = qMax(qreal(0), qreal(startY));
endX = qMin(qreal(map()->width()), qreal(endX));
endY = qMin(qreal(map()->height()), qreal(endY));
}

QPen gridPen = makeGridPen(painter->device(), gridColor);
painter->setPen(gridPen);
Expand Down Expand Up @@ -243,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.

const Cell &cell = layer->cellAt(columnItr);
if (!cell.isEmpty()) {
Tile *tile = cell.tile();
Expand Down
2 changes: 1 addition & 1 deletion src/libtiled/isometricrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class TILEDSHARED_EXPORT IsometricRenderer : public MapRenderer
public:
IsometricRenderer(const Map *map) : MapRenderer(map) {}

QSize mapSize() const override;
QRect mapBoundingRect() const override;

QRect boundingRect(const QRect &rect) const override;

Expand Down
5 changes: 3 additions & 2 deletions src/libtiled/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@
using namespace Tiled;

Map::Map(Orientation orientation,
int width, int height, int tileWidth, int tileHeight):
int width, int height, int tileWidth, int tileHeight, bool infinite):
Object(MapType),
mOrientation(orientation),
mRenderOrder(RightDown),
mWidth(width),
mHeight(height),
mTileWidth(tileWidth),
mTileHeight(tileHeight),
mInfinite(infinite),
mHexSideLength(0),
mStaggerAxis(StaggerY),
mStaggerIndex(StaggerOdd),
Expand All @@ -66,6 +67,7 @@ Map::Map(const Map &map):
mHeight(map.mHeight),
mTileWidth(map.mTileWidth),
mTileHeight(map.mTileHeight),
mInfinite(map.mInfinite),
mHexSideLength(map.mHexSideLength),
mStaggerAxis(map.mStaggerAxis),
mStaggerIndex(map.mStaggerIndex),
Expand Down Expand Up @@ -296,7 +298,6 @@ void Map::initializeObjectIds(ObjectGroup &objectGroup)
}
}


QString Tiled::staggerAxisToString(Map::StaggerAxis staggerAxis)
{
switch (staggerAxis) {
Expand Down
8 changes: 7 additions & 1 deletion src/libtiled/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ class TILEDSHARED_EXPORT Map : public Object
*/
Map(Orientation orientation,
int width, int height,
int tileWidth, int tileHeight);
int tileWidth, int tileHeight,
bool infinite = false);

/**
* Copy constructor. Makes sure that a deep-copy of the layers is created.
Expand Down Expand Up @@ -192,6 +193,10 @@ class TILEDSHARED_EXPORT Map : public Object
*/
void setTileHeight(int height) { mTileHeight = height; }

bool infinite() const { return mInfinite; }

void setInfinite(bool infinite) { mInfinite = infinite; }

/**
* Returns the size of one tile. Provided for convenience.
*/
Expand Down Expand Up @@ -387,6 +392,7 @@ class TILEDSHARED_EXPORT Map : public Object
int mHeight;
int mTileWidth;
int mTileHeight;
bool mInfinite;
int mHexSideLength;
StaggerAxis mStaggerAxis;
StaggerIndex mStaggerIndex;
Expand Down
Loading