Skip to content

Commit

Permalink
Added custom output chunk size option to map properties (#2130)
Browse files Browse the repository at this point in the history
Closes #2121
  • Loading branch information
RPGHacker authored and bjorn committed Jul 10, 2019
1 parent 711bbfa commit e297ae7
Show file tree
Hide file tree
Showing 15 changed files with 193 additions and 31 deletions.
2 changes: 2 additions & 0 deletions src/libtiled/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Map::Map(Orientation orientation,
mHexSideLength(0),
mStaggerAxis(StaggerY),
mStaggerIndex(StaggerOdd),
mChunkSize(CHUNK_SIZE, CHUNK_SIZE),
mDrawMarginsDirty(true),
mLayerDataFormat(Base64Zlib),
mNextLayerId(1),
Expand Down Expand Up @@ -337,6 +338,7 @@ Map *Map::clone() const
o->mStaggerAxis = mStaggerAxis;
o->mStaggerIndex = mStaggerIndex;
o->mBackgroundColor = mBackgroundColor;
o->mChunkSize = mChunkSize;
o->mDrawMargins = mDrawMargins;
o->mDrawMarginsDirty = mDrawMarginsDirty;
for (const Layer *layer : mLayers) {
Expand Down
11 changes: 11 additions & 0 deletions src/libtiled/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,16 @@ class TILEDSHARED_EXPORT Map : public Object
*/
void setBackgroundColor(QColor color) { mBackgroundColor = color; }

/**
* Returns the chunk size used when saving tile layers of this map.
*/
QSize chunkSize() const { return mChunkSize; }

/**
* Sets the chunk size used when saving tile layers of this map.
*/
void setChunkSize(QSize size) { mChunkSize = size; }

/**
* Returns whether the given \a tileset is used by any tile layer of this
* map.
Expand Down Expand Up @@ -470,6 +480,7 @@ class TILEDSHARED_EXPORT Map : public Object
StaggerAxis mStaggerAxis;
StaggerIndex mStaggerIndex;
QColor mBackgroundColor;
QSize mChunkSize;
mutable QMargins mDrawMargins;
mutable bool mDrawMarginsDirty;
QList<Layer*> mLayers;
Expand Down
8 changes: 8 additions & 0 deletions src/libtiled/mapreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,14 @@ void MapReaderPrivate::readTileLayerData(TileLayer &tileLayer)

mMap->setLayerDataFormat(layerDataFormat);

int chunkWidth = atts.value(QLatin1String("outputchunkwidth")).toInt();
int chunkHeight = atts.value(QLatin1String("outputchunkheight")).toInt();

chunkWidth = chunkWidth == 0 ? CHUNK_SIZE : qMax(CHUNK_SIZE_MIN, chunkWidth);
chunkHeight = chunkHeight == 0 ? CHUNK_SIZE : qMax(CHUNK_SIZE_MIN, chunkHeight);

mMap->setChunkSize(QSize(chunkWidth, chunkHeight));

readTileLayerRect(tileLayer,
layerDataFormat,
encoding,
Expand Down
26 changes: 18 additions & 8 deletions src/libtiled/maptovariantconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ QVariant MapToVariantConverter::toVariant(const Map &map, const QDir &mapDir)
mapVariant[QLatin1String("tilesets")] = tilesetVariants;

mapVariant[QLatin1String("layers")] = toVariant(map.layers(),
map.layerDataFormat());
map.layerDataFormat(),
map.chunkSize());

return mapVariant;
}
Expand Down Expand Up @@ -385,14 +386,15 @@ QVariant MapToVariantConverter::toVariant(const WangColor &wangColor) const
}

QVariant MapToVariantConverter::toVariant(const QList<Layer *> &layers,
Map::LayerDataFormat format) const
Map::LayerDataFormat format,
QSize chunkSize) const
{
QVariantList layerVariants;

for (const Layer *layer : layers) {
switch (layer->layerType()) {
case Layer::TileLayerType:
layerVariants << toVariant(*static_cast<const TileLayer*>(layer), format);
layerVariants << toVariant(*static_cast<const TileLayer*>(layer), format, chunkSize);
break;
case Layer::ObjectGroupType:
layerVariants << toVariant(*static_cast<const ObjectGroup*>(layer));
Expand All @@ -401,15 +403,16 @@ QVariant MapToVariantConverter::toVariant(const QList<Layer *> &layers,
layerVariants << toVariant(*static_cast<const ImageLayer*>(layer));
break;
case Layer::GroupLayerType:
layerVariants << toVariant(*static_cast<const GroupLayer*>(layer), format);
layerVariants << toVariant(*static_cast<const GroupLayer*>(layer), format, chunkSize);
}
}

return layerVariants;
}

QVariant MapToVariantConverter::toVariant(const TileLayer &tileLayer,
Map::LayerDataFormat format) const
Map::LayerDataFormat format,
QSize chunkSize) const
{
QVariantMap tileLayerVariant;
tileLayerVariant[QLatin1String("type")] = QLatin1String("tilelayer");
Expand Down Expand Up @@ -446,9 +449,14 @@ QVariant MapToVariantConverter::toVariant(const TileLayer &tileLayer,
}

if (tileLayer.map()->infinite()) {
if (chunkSize.width() != CHUNK_SIZE || chunkSize.height() != CHUNK_SIZE) {
tileLayerVariant[QLatin1String("outputchunkwidth")] = chunkSize.width();
tileLayerVariant[QLatin1String("outputchunkheight")] = chunkSize.height();
}

QVariantList chunkVariants;

const auto chunks = tileLayer.sortedChunksToWrite();
const auto chunks = tileLayer.sortedChunksToWrite(chunkSize);
for (const QRect &rect : chunks) {
QVariantMap chunkVariant;

Expand Down Expand Up @@ -649,15 +657,17 @@ QVariant MapToVariantConverter::toVariant(const ImageLayer &imageLayer) const
}

QVariant MapToVariantConverter::toVariant(const GroupLayer &groupLayer,
Map::LayerDataFormat format) const
Map::LayerDataFormat format,
QSize chunkSize) const
{
QVariantMap groupLayerVariant;
groupLayerVariant[QLatin1String("type")] = QLatin1String("group");

addLayerAttributes(groupLayerVariant, groupLayer);

groupLayerVariant[QLatin1String("layers")] = toVariant(groupLayer.layers(),
format);
format,
chunkSize);

return groupLayerVariant;
}
Expand Down
6 changes: 3 additions & 3 deletions src/libtiled/maptovariantconverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ class TILEDSHARED_EXPORT MapToVariantConverter
QVariant propertyTypesToVariant(const Properties &properties) const;
QVariant toVariant(const WangSet &wangSet) const;
QVariant toVariant(const WangColor &wangColor) const;
QVariant toVariant(const QList<Layer*> &layers, Map::LayerDataFormat format) const;
QVariant toVariant(const TileLayer &tileLayer, Map::LayerDataFormat format) const;
QVariant toVariant(const QList<Layer*> &layers, Map::LayerDataFormat format, QSize chunkSize) const;
QVariant toVariant(const TileLayer &tileLayer, Map::LayerDataFormat format, QSize chunkSize) const;
QVariant toVariant(const ObjectGroup &objectGroup) const;
QVariant toVariant(const MapObject &object) const;
QVariant toVariant(const TextData &textData) const;
QVariant toVariant(const ImageLayer &imageLayer) const;
QVariant toVariant(const GroupLayer &groupLayer, Map::LayerDataFormat format) const;
QVariant toVariant(const GroupLayer &groupLayer, Map::LayerDataFormat format, QSize chunkSize) const;

void addTileLayerData(QVariantMap &variant,
const TileLayer &tileLayer,
Expand Down
10 changes: 9 additions & 1 deletion src/libtiled/mapwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class MapWriterPrivate
QString mError;
Map::LayerDataFormat mLayerDataFormat;
bool mDtdEnabled;
QSize mChunkSize;

private:
void writeMap(QXmlStreamWriter &w, const Map &map);
Expand Down Expand Up @@ -114,6 +115,7 @@ class MapWriterPrivate
MapWriterPrivate::MapWriterPrivate()
: mLayerDataFormat(Map::Base64Zlib)
, mDtdEnabled(false)
, mChunkSize(CHUNK_SIZE, CHUNK_SIZE)
, mUseAbsolutePaths(false)
{
}
Expand Down Expand Up @@ -149,6 +151,7 @@ void MapWriterPrivate::writeMap(const Map *map, QIODevice *device,
mMapDir = QDir(path);
mUseAbsolutePaths = path.isEmpty();
mLayerDataFormat = map->layerDataFormat();
mChunkSize = map->chunkSize();

AutoFormattingWriter writer(device);
writer.writeStartDocument();
Expand Down Expand Up @@ -588,7 +591,12 @@ void MapWriterPrivate::writeTileLayer(QXmlStreamWriter &w,
w.writeAttribute(QLatin1String("compression"), compression);

if (tileLayer.map()->infinite()) {
const auto chunks = tileLayer.sortedChunksToWrite();
if (mChunkSize.width() != CHUNK_SIZE || mChunkSize.height() != CHUNK_SIZE) {
w.writeAttribute(QLatin1String("outputchunkwidth"), QString::number(mChunkSize.width()));
w.writeAttribute(QLatin1String("outputchunkheight"), QString::number(mChunkSize.height()));
}

const auto chunks = tileLayer.sortedChunksToWrite(mChunkSize);
for (const QRect &rect : chunks) {
w.writeStartElement(QLatin1String("chunk"));
w.writeAttribute(QLatin1String("x"), QString::number(rect.x()));
Expand Down
1 change: 1 addition & 0 deletions src/libtiled/tiled.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ enum LoadingStatus {
};

const int CHUNK_SIZE = 16;
const int CHUNK_SIZE_MIN = 4;
const int CHUNK_MASK = CHUNK_SIZE - 1;

static const char TILES_MIMETYPE[] = "application/vnd.tile.list";
Expand Down
65 changes: 60 additions & 5 deletions src/libtiled/tilelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include <algorithm>
#include <memory>

#include <QSet>

using namespace Tiled;

Cell Cell::empty;
Expand Down Expand Up @@ -760,19 +762,72 @@ static bool compareRectPos(const QRect &a, const QRect &b)
* This function is used to determine the chunks to write when saving a tile
* layer.
*/
QVector<QRect> TileLayer::sortedChunksToWrite() const
QVector<QRect> TileLayer::sortedChunksToWrite(QSize chunkSize) const
{
QVector<QRect> chunksToWrite;
chunksToWrite.reserve(mChunks.size());
QSet<QPoint> existingChunks;

bool isNativeChunkSize = (chunkSize.width() == CHUNK_SIZE &&
chunkSize.height() == CHUNK_SIZE);

if (isNativeChunkSize)
chunksToWrite.reserve(mChunks.size());

QHashIterator<QPoint, Chunk> it(mChunks);
while (it.hasNext()) {
it.next();
if (!it.value().isEmpty()) {
const QPoint p = it.key();
const Chunk &chunk = it.next().value();
if (chunk.isEmpty())
continue;

const QPoint &p = it.key();

if (isNativeChunkSize) {
// If the desired chunk size is equal to our native chunk size,
// then we just we just have to iterate our chunk list and return
// the bounds of each chunk.
chunksToWrite.append(QRect(p.x() * CHUNK_SIZE,
p.y() * CHUNK_SIZE,
CHUNK_SIZE, CHUNK_SIZE));
} else {
// If the desired chunk size is not the native size, we have to do
// a bit of extra work and "rearrange" chunks as we iterate our
// list. We do this by iterating every cell in a chunk. If it's not
// empty, we check what chunk it should go into with the new chunk
// size. If that chunk doesn't exist yet, we create it.
//
// NOTE: Rather than checking every cell in every chunk, we could
// also just test which "new" chunks our "old" chunk would
// intersect with and return all of those, this would be faster.
// However, that way we could end up with completely empty chunks,
// so we'll take the slower route and iterate all cells instead to
// avoid that.
int oldChunkStartX = p.x() * CHUNK_SIZE;
int oldChunkStartY = p.y() * CHUNK_SIZE;

for (int y = 0; y < CHUNK_SIZE; ++y) {
for (int x = 0; x < CHUNK_SIZE; ++x) {
const Cell &cell = chunk.cellAt(x, y);

if (!cell.isEmpty()) {
int tileX = oldChunkStartX + x;
int tileY = oldChunkStartY + y;

// Nasty conditionals because of potentially negative
// chunk start position. Modulo with negative numbers
// is weird and unintuitive in C++...
int moduloX = tileX % chunkSize.width();
int newChunkStartX = tileX - (moduloX < 0 ? moduloX + chunkSize.width() : moduloX);
int moduloY = tileY % chunkSize.height();
int newChunkStartY = tileY - (moduloY < 0 ? moduloY + chunkSize.height() : moduloY);
QPoint startPoint(newChunkStartX, newChunkStartY);

if (!existingChunks.contains(startPoint)) {
existingChunks.insert(startPoint);
chunksToWrite.append(QRect(newChunkStartX, newChunkStartY, chunkSize.width(), chunkSize.height()));
}
}
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/libtiled/tilelayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ class TILEDSHARED_EXPORT TileLayer : public Layer
const_iterator begin() const { return const_iterator(mChunks.begin(), mChunks.end()); }
const_iterator end() const { return const_iterator(mChunks.end(), mChunks.end()); }

QVector<QRect> sortedChunksToWrite() const;
QVector<QRect> sortedChunksToWrite(QSize chunkSize) const;

protected:
TileLayer *initializeClone(TileLayer *clone) const;
Expand Down
8 changes: 8 additions & 0 deletions src/libtiled/varianttomapconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,14 @@ std::unique_ptr<TileLayer> VariantToMapConverter::toTileLayer(const QVariantMap
}
mMap->setLayerDataFormat(layerDataFormat);

int chunkWidth = variantMap[QLatin1String("outputchunkwidth")].toInt();
int chunkHeight = variantMap[QLatin1String("outputchunkheight")].toInt();

chunkWidth = chunkWidth == 0 ? CHUNK_SIZE : qMax(CHUNK_SIZE_MIN, chunkWidth);
chunkHeight = chunkHeight == 0 ? CHUNK_SIZE : qMax(CHUNK_SIZE_MIN, chunkHeight);

mMap->setChunkSize(QSize(chunkWidth, chunkHeight));

if (dataVariant.isValid() && !dataVariant.isNull()) {
if (!readTileLayerData(*tileLayer, dataVariant, layerDataFormat,
QRect(startX, startY, tileLayer->width(), tileLayer->height()))) {
Expand Down
Loading

0 comments on commit e297ae7

Please sign in to comment.