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

Custom output chunk size can now be specified in the map properties #2130

Merged
merged 4 commits into from
Jul 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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