Exemplo n.º 1
0
void StampBrush::endCapture()
{
    if (mBrushBehavior != Capture)
        return;

    mBrushBehavior = Free;

    TileLayer *tileLayer = currentTileLayer();
    Q_ASSERT(tileLayer);

    // Intersect with the layer and translate to layer coordinates
    QRect captured = capturedArea();
    captured &= QRect(tileLayer->x(), tileLayer->y(),
                      tileLayer->width(), tileLayer->height());

    if (captured.isValid()) {
        captured.translate(-tileLayer->x(), -tileLayer->y());
        Map *map = tileLayer->map();
        TileLayer *capture = tileLayer->copy(captured);
        Map *stamp = new Map(map->orientation(),
                             capture->width(),
                             capture->height(),
                             map->tileWidth(),
                             map->tileHeight());

        // Add tileset references to map
        foreach (const SharedTileset &tileset, capture->usedTilesets())
            stamp->addTileset(tileset);

        stamp->addLayer(capture);

        emit stampCaptured(TileStamp(stamp));
    } else {
Exemplo n.º 2
0
void StampBrush::endCapture()
{
    if (mBrushBehavior != Capture)
        return;

    mBrushBehavior = Free;

    TileLayer *tileLayer = currentTileLayer();
    Q_ASSERT(tileLayer);

    // Intersect with the layer and translate to layer coordinates
    QRect captured = capturedArea();
    captured.intersect(QRect(tileLayer->x(), tileLayer->y(),
                             tileLayer->width(), tileLayer->height()));

    if (captured.isValid()) {
        captured.translate(-tileLayer->x(), -tileLayer->y());
        TileLayer *capture = tileLayer->copy(captured);
        emit currentTilesChanged(capture);
        // A copy will have been created, so delete this version
        delete capture;
    } else {
        updatePosition();
    }
}
Exemplo n.º 3
0
/**
 * Returns a new stamp where all variations have been flipped in the given
 * \a direction.
 */
TileStamp TileStamp::flipped(FlipDirection direction) const
{
    TileStamp flipped(*this);
    flipped.d.detach();

    for (const TileStampVariation &variation : flipped.variations()) {
        TileLayer *layer = variation.tileLayer();

        if (variation.map->isStaggered()) {
            Map::StaggerAxis staggerAxis = variation.map->staggerAxis();

            if (staggerAxis == Map::StaggerY) {
                if ((direction == FlipVertically && !(layer->height() & 1)) || direction == FlipHorizontally)
                    variation.map->invertStaggerIndex();

            } else {
                if ((direction == FlipHorizontally && !(layer->width() & 1)) || direction == FlipVertically)
                    variation.map->invertStaggerIndex();
            }
        }

        if (variation.map->orientation() == Map::Hexagonal)
            layer->flipHexagonal(direction);
        else
            layer->flip(direction);
    }

    return flipped;
}
Exemplo n.º 4
0
// Writer
bool DroidcraftPlugin::write(const Tiled::Map *map, const QString &fileName)
{
    using namespace Tiled;

    // Check layer count and type
    if (map->layerCount() != 1 || !map->layerAt(0)->isTileLayer()) {
        mError = tr("The map needs to have exactly one tile layer!");
        return false;
    }

    TileLayer *mapLayer = map->layerAt(0)->asTileLayer();

    // Check layer size
    if (mapLayer->width() != 48 || mapLayer->height() != 48) {
        mError = tr("The layer must have a size of 48 x 48 tiles!");
        return false;
    }

    // Create QByteArray and compress it
    QByteArray uncompressed = QByteArray(48 * 48, 0);

    const int width = mapLayer->width();
    const int height = mapLayer->height();

    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            if (Tile *tile = mapLayer->cellAt(x, y).tile)
                uncompressed[y * width + x] = (unsigned char) tile->id();
        }
    }

    QByteArray compressed = compress(uncompressed, Gzip);

    // Write QByteArray
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly)) {
        mError = tr("Could not open file for writing.");
        return false;
    }

    file.write(compressed);
    file.close();

    return true;
}
Exemplo n.º 5
0
static void fillWithStamp(TileLayer &layer,
                          const TileStamp &stamp,
                          const QRegion &mask)
{
    const QSize size = stamp.maxSize();

    // Fill the entire layer with random variations of the stamp
    for (int y = 0; y < layer.height(); y += size.height()) {
        for (int x = 0; x < layer.width(); x += size.width()) {
            const TileStampVariation variation = stamp.randomVariation();
            layer.setCells(x, y, variation.tileLayer());
        }
    }

    // Erase tiles outside of the masked region. This can easily be faster than
    // avoiding to place tiles outside of the region in the first place.
    layer.erase(QRegion(0, 0, layer.width(), layer.height()) - mask);
}
Exemplo n.º 6
0
void StampBrush::endCapture()
{
    if (mBrushBehavior != Capture)
        return;

    mBrushBehavior = Free;

    TileLayer *tileLayer = currentTileLayer();
    Q_ASSERT(tileLayer);

    // Intersect with the layer and translate to layer coordinates
    QRect captured = capturedArea();
    captured &= QRect(tileLayer->x(), tileLayer->y(),
                      tileLayer->width(), tileLayer->height());

    if (captured.isValid()) {
        captured.translate(-tileLayer->x(), -tileLayer->y());
        Map *map = tileLayer->map();
        TileLayer *capture = tileLayer->copy(captured);
        Map *stamp = new Map(map->orientation(),
                             capture->width(),
                             capture->height(),
                             map->tileWidth(),
                             map->tileHeight());

        //gets if the relative stagger should be the same as the base layer
        int staggerIndexOffSet;
        if (tileLayer->map()->staggerAxis() == Map::StaggerX)
            staggerIndexOffSet = captured.x() % 2;
        else
            staggerIndexOffSet = captured.y() % 2;

        stamp->setStaggerAxis(map->staggerAxis());
        stamp->setStaggerIndex((Map::StaggerIndex)((map->staggerIndex() + staggerIndexOffSet) % 2));

        // Add tileset references to map
        foreach (const SharedTileset &tileset, capture->usedTilesets())
            stamp->addTileset(tileset);

        stamp->addLayer(capture);

        emit stampCaptured(TileStamp(stamp));
    } else {
Exemplo n.º 7
0
TileLayer *VariantToMapConverter::toTileLayer(const QVariantMap &variantMap)
{
    const QString name = variantMap["name"].toString();
    const int width = variantMap["width"].toInt();
    const int height = variantMap["height"].toInt();
    const QVariantList dataVariantList = variantMap["data"].toList();

    if (dataVariantList.size() != width * height) {
        mError = tr("Corrupt layer data for layer '%1'").arg(name);
        return 0;
    }

    TileLayer *tileLayer = new TileLayer(name,
                                         variantMap["x"].toInt(),
                                         variantMap["y"].toInt(),
                                         width, height);

    const qreal opacity = variantMap["opacity"].toReal();
    const bool visible = variantMap["visible"].toBool();

    tileLayer->setOpacity(opacity);
    tileLayer->setVisible(visible);

    int x = 0;
    int y = 0;
    bool ok;

    foreach (const QVariant &gidVariant, dataVariantList) {
        const uint gid = gidVariant.toUInt(&ok);
        if (!ok) {
            mError = tr("Unable to parse tile at (%1,%2) on layer '%3'")
                    .arg(x).arg(y).arg(tileLayer->name());

            delete tileLayer;
            tileLayer = 0;
            break;
        }

        const Cell cell = mGidMapper.gidToCell(gid, ok);

        tileLayer->setCell(x, y, cell);

        x++;
        if (x >= tileLayer->width()) {
            x = 0;
            y++;
        }
    }

    return tileLayer;
}
Exemplo n.º 8
0
void BucketFillTool::updateRandomList()
{
    mRandomList.clear();
    mMissingTilesets.clear();

    foreach (const TileStampVariation &variation, mStamp.variations()) {
        TileLayer *tileLayer = static_cast<TileLayer*>(variation.map->layerAt(0));
        mapDocument()->unifyTilesets(variation.map, mMissingTilesets);
        for (int x = 0; x < tileLayer->width(); x++)
            for (int y = 0; y < tileLayer->height(); y++)
                if (!tileLayer->cellAt(x, y).isEmpty())
                    mRandomList.append(tileLayer->cellAt(x, y));
    }
}
Exemplo n.º 9
0
/**
 * Returns a new stamp where all variations have been rotated in the given
 * \a direction.
 */
TileStamp TileStamp::rotated(RotateDirection direction) const
{
    TileStamp rotated(*this);
    rotated.d.detach();

    foreach (const TileStampVariation &variation, rotated.variations()) {
        TileLayer *layer = static_cast<TileLayer*>(variation.map->layerAt(0));
        layer->rotate(direction);

        variation.map->setWidth(layer->width());
        variation.map->setHeight(layer->height());
    }

    return rotated;
}
Exemplo n.º 10
0
void TerrainBrush::updateBrush(QPoint cursorPos, const QVector<QPoint> *list)
{
    // get the current tile layer
    TileLayer *currentLayer = currentTileLayer();
    Q_ASSERT(currentLayer);

    int layerWidth = currentLayer->width();
    int layerHeight = currentLayer->height();
    int numTiles = layerWidth * layerHeight;
    int paintCorner = 0;

    // if we are in vertex paint mode, the bottom right corner on the map will appear as an invalid tile offset...
    if (mBrushMode == PaintVertex) {
        if (cursorPos.x() == layerWidth) {
            cursorPos.setX(cursorPos.x() - 1);
            paintCorner |= 1;
        }
        if (cursorPos.y() == layerHeight) {
            cursorPos.setY(cursorPos.y() - 1);
            paintCorner |= 2;
        }
    }

    // if the cursor is outside of the map, bail out
    if (!currentLayer->bounds().contains(cursorPos))
        return;

    // TODO: this seems like a problem... there's nothing to say that 2 adjacent tiles are from the same tileset, or have any relation to eachother...
    Tileset *terrainTileset = mTerrain ? mTerrain->tileset() : NULL;

    // allocate a buffer to build the terrain tilemap (TODO: this could be retained per layer to save regular allocation)
    Tile **newTerrain = new Tile*[numTiles];

    // allocate a buffer of flags for each tile that may be considered (TODO: this could be retained per layer to save regular allocation)
    char *checked = new char[numTiles];
    memset(checked, 0, numTiles);

    // create a consideration list, and push the start points
    QList<QPoint> transitionList;
    int initialTiles = 0;

    if (list) {
        // if we were supplied a list of start points
        foreach (const QPoint &p, *list) {
            transitionList.push_back(p);
            ++initialTiles;
        }
    } else {
Exemplo n.º 11
0
/**
 * Returns a new stamp where all variations have been rotated in the given
 * \a direction.
 */
TileStamp TileStamp::rotated(RotateDirection direction) const
{
    TileStamp rotated(*this);
    rotated.d.detach();

    for (const TileStampVariation &variation : rotated.variations()) {
        TileLayer *layer = variation.tileLayer();
        if (variation.map->orientation() == Map::Hexagonal)
            layer->rotateHexagonal(direction, variation.map);
        else
            layer->rotate(direction);

        variation.map->setWidth(layer->width());
        variation.map->setHeight(layer->height());
    }

    return rotated;
}
Exemplo n.º 12
0
/**
 * Updates the list used random stamps.
 * This is done by taking all non-null tiles from the original stamp mStamp.
 */
void StampBrush::updateRandomList()
{
    mRandomCellPicker.clear();
    mMissingTilesets.clear();

    if (mStamp.isEmpty())
        return;

    foreach (const TileStampVariation &variation, mStamp.variations()) {
        TileLayer *tileLayer = static_cast<TileLayer*>(variation.map->layerAt(0));
        mapDocument()->unifyTilesets(variation.map, mMissingTilesets);
        for (int x = 0; x < tileLayer->width(); x++) {
            for (int y = 0; y < tileLayer->height(); y++) {
                const Cell &cell = tileLayer->cellAt(x, y);
                if (!cell.isEmpty())
                    mRandomCellPicker.add(cell, cell.tile->probability());
            }
        }
    }
}
Exemplo n.º 13
0
/**
 * Updates the list used random stamps.
 * This is done by taking all non-null tiles from the original stamp mStamp.
 */
void StampBrush::updateRandomList()
{
    mRandomCellPicker.clear();

    if (!mIsRandom)
        return;

    mMissingTilesets.clear();

    for (const TileStampVariation &variation : mStamp.variations()) {
        mapDocument()->unifyTilesets(variation.map, mMissingTilesets);
        TileLayer *tileLayer = variation.tileLayer();
        for (int x = 0; x < tileLayer->width(); x++) {
            for (int y = 0; y < tileLayer->height(); y++) {
                const Cell &cell = tileLayer->cellAt(x, y);
                if (const Tile *tile = cell.tile())
                    mRandomCellPicker.add(cell, tile->probability());
            }
        }
    }
}
Exemplo n.º 14
0
void StampBrush::doPaint(bool mergeable, int whereX, int whereY)
{
    TileLayer *stamp = brushItem()->tileLayer();

    if (!stamp)
        return;

    // This method shouldn't be called when current layer is not a tile layer
    TileLayer *tileLayer = currentTileLayer();
    Q_ASSERT(tileLayer);

    if (!tileLayer->bounds().intersects(QRect(whereX, whereY,
                                              stamp->width(),
                                              stamp->height())))
        return;

    PaintTileLayer *paint = new PaintTileLayer(mapDocument(), tileLayer,
                            whereX, whereY, stamp);
    paint->setMergeable(mergeable);
    mapDocument()->undoStack()->push(paint);
    mapDocument()->emitRegionEdited(brushItem()->tileRegion(), tileLayer);
}
Exemplo n.º 15
0
void test_MapReader::loadMap()
{
    MapReader reader;
    Map *map = reader.readMap("../data/mapobject.tmx");

    // TODO: Also test tilesets (internal and external), properties and tile
    // layer data.

    QVERIFY(map);
    QCOMPARE(map->layerCount(), 2);
    QCOMPARE(map->width(), 100);
    QCOMPARE(map->height(), 80);
    QCOMPARE(map->tileWidth(), 32);
    QCOMPARE(map->tileHeight(), 32);

    TileLayer *tileLayer = dynamic_cast<TileLayer*>(map->layerAt(0));

    QVERIFY(tileLayer);
    QCOMPARE(tileLayer->width(), 100);
    QCOMPARE(tileLayer->height(), 80);

    ObjectGroup *objectGroup = dynamic_cast<ObjectGroup*>(map->layerAt(1));

    QVERIFY(objectGroup);
    QCOMPARE(objectGroup->name(), QLatin1String("Objects"));
    QCOMPARE(objectGroup->objects().count(), 1);

    MapObject *mapObject = objectGroup->objects().at(0);

    QCOMPARE(mapObject->name(), QLatin1String("Some object"));
    QCOMPARE(mapObject->type(), QLatin1String("WARP"));
    QCOMPARE(mapObject->x(), qreal(200));
    QCOMPARE(mapObject->y(), qreal(200));
    QCOMPARE(mapObject->width(), qreal(128));
    QCOMPARE(mapObject->height(), qreal(64));
}
Exemplo n.º 16
0
QVariant MapToVariantConverter::toVariant(const TileLayer &tileLayer,
                                          Map::LayerDataFormat format) const
{
    QVariantMap tileLayerVariant;
    tileLayerVariant[QLatin1String("type")] = QLatin1String("tilelayer");

    QRect bounds = tileLayer.bounds().translated(-tileLayer.position());

    if (tileLayer.map()->infinite()) {
        tileLayerVariant[QLatin1String("width")] = bounds.width();
        tileLayerVariant[QLatin1String("height")] = bounds.height();
        tileLayerVariant[QLatin1String("startx")] = bounds.left();
        tileLayerVariant[QLatin1String("starty")] = bounds.top();
    } else {
        tileLayerVariant[QLatin1String("width")] = tileLayer.width();
        tileLayerVariant[QLatin1String("height")] = tileLayer.height();
    }

    addLayerAttributes(tileLayerVariant, tileLayer);

    switch (format) {
    case Map::XML:
    case Map::CSV:
        break;
    case Map::Base64:
    case Map::Base64Zlib:
    case Map::Base64Gzip:
        tileLayerVariant[QLatin1String("encoding")] = QLatin1String("base64");

        if (format == Map::Base64Zlib)
            tileLayerVariant[QLatin1String("compression")] = QLatin1String("zlib");
        else if (format == Map::Base64Gzip)
            tileLayerVariant[QLatin1String("compression")] = QLatin1String("gzip");

        break;
    }

    if (tileLayer.map()->infinite()) {
        QVariantList chunkVariants;

        for (const QRect &rect : tileLayer.sortedChunksToWrite()) {
            QVariantMap chunkVariant;

            chunkVariant[QLatin1String("x")] = rect.x();
            chunkVariant[QLatin1String("y")] = rect.y();
            chunkVariant[QLatin1String("width")] = rect.width();
            chunkVariant[QLatin1String("height")] = rect.height();

            addTileLayerData(chunkVariant, tileLayer, format, rect);

            chunkVariants.append(chunkVariant);
        }

        tileLayerVariant[QLatin1String("chunks")] = chunkVariants;
    } else {
        addTileLayerData(tileLayerVariant, tileLayer, format,
                         QRect(0, 0, tileLayer.width(), tileLayer.height()));
    }

    return tileLayerVariant;
}
Exemplo n.º 17
0
void BucketFillTool::tilePositionChanged(const QPoint &tilePos)
{
    if (mStamp.isEmpty())
        return;

    bool shiftPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier;
    bool fillRegionChanged = false;

    // Make sure that a tile layer is selected
    TileLayer *tileLayer = currentTileLayer();
    if (!tileLayer)
        return;

    // todo: When there are multiple variations, it would make sense to choose
    // random variations while filling. When the variations have different
    // sizes, probably the bounding box of all variations should be used.
    Map *variation = mStamp.randomVariation();
    TileLayer *stampLayer = static_cast<TileLayer*>(variation->layerAt(0));

    // Skip filling if the stamp is empty
    if (!stampLayer || stampLayer->isEmpty())
        return;

    TilePainter regionComputer(mapDocument(), tileLayer);
    // If the stamp is a single tile, ignore it when making the region
    if (stampLayer->width() == 1 && stampLayer->height() == 1 && !shiftPressed &&
            stampLayer->cellAt(0, 0) == regionComputer.cellAt(tilePos.x(),
                                                              tilePos.y()))
        return;

    // This clears the connections so we don't get callbacks
    clearConnections(mapDocument());

    // Optimization: we don't need to recalculate the fill area
    // if the new mouse position is still over the filled region
    // and the shift modifier hasn't changed.
    if (!mFillRegion.contains(tilePos) || shiftPressed != mLastShiftStatus || mIsRandom) {

        // Clear overlay to make way for a new one
        clearOverlay();

        // Cache information about how the fill region was created
        mLastShiftStatus = shiftPressed;

        // Get the new fill region
        if (!shiftPressed) {
            // If not holding shift, a region is generated from the current pos
            mFillRegion = regionComputer.computePaintableFillRegion(tilePos);
        } else {
            // If holding shift, the region is the selection bounds
            mFillRegion = mapDocument()->selectedArea();

            // Fill region is the whole map if there is no selection
            if (mFillRegion.isEmpty())
                mFillRegion = tileLayer->bounds();

            // The mouse needs to be in the region
            if (!mFillRegion.contains(tilePos))
                mFillRegion = QRegion();
        }
        fillRegionChanged = true;
    }

    // Ensure that a fill region was created before making an overlay layer
    if (mFillRegion.isEmpty())
        return;

    if (mLastRandomStatus != mIsRandom) {
        mLastRandomStatus = mIsRandom;
        fillRegionChanged = true;
    }

    if (!mFillOverlay) {
        // Create a new overlay region
        const QRect fillBounds = mFillRegion.boundingRect();
        mFillOverlay = SharedTileLayer(new TileLayer(QString(),
                                                     fillBounds.x(),
                                                     fillBounds.y(),
                                                     fillBounds.width(),
                                                     fillBounds.height()));
    }

    // Paint the new overlay
    if (!mIsRandom) {
        if (fillRegionChanged) {
            mMissingTilesets.clear();
            mapDocument()->unifyTilesets(variation, mMissingTilesets);

            TilePainter tilePainter(mapDocument(), mFillOverlay.data());
            tilePainter.drawStamp(stampLayer, mFillRegion);
        }
    } else {
        randomFill(mFillOverlay.data(), mFillRegion);
        fillRegionChanged = true;
    }

    if (fillRegionChanged) {
        // Update the brush item to draw the overlay
        brushItem()->setTileLayer(mFillOverlay);
    }
    // Create connections to know when the overlay should be cleared
    makeConnections();
}
Exemplo n.º 18
0
void BucketFillTool::tilePositionChanged(const QPoint &tilePos)
{
    bool shiftPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier;

    // Optimization: we don't need to recalculate the fill area
    // if the new mouse position is still over the filled region
    // and the shift modifier hasn't changed.
    if (mFillRegion.contains(tilePos) && shiftPressed == mLastShiftStatus)
        return;

    // Cache information about how the fill region was created
    mLastShiftStatus = shiftPressed;

    // Clear overlay to make way for a new one
    // This also clears the connections so we don't get callbacks
    clearOverlay();

    // Skip filling if the stamp is empty
    if (!mStamp || mStamp->isEmpty())
        return;

    // Make sure that a tile layer is selected
    TileLayer *tileLayer = currentTileLayer();
    if (!tileLayer)
        return;

    // Get the new fill region
    if (!shiftPressed) {
        // If not holding shift, a region is generated from the current pos
        TilePainter regionComputer(mapDocument(), tileLayer);

        // If the stamp is a single tile, ignore it when making the region
        if (mStamp->width() == 1 && mStamp->height() == 1 &&
            mStamp->cellAt(0, 0) == regionComputer.cellAt(tilePos.x(),
                                                          tilePos.y()))
            return;

        mFillRegion = regionComputer.computeFillRegion(tilePos);
    } else {
        // If holding shift, the region is the selection bounds
        mFillRegion = mapDocument()->tileSelection();

        // Fill region is the whole map is there is no selection
        if (mFillRegion.isEmpty())
            mFillRegion = tileLayer->bounds();

        // The mouse needs to be in the region
        if (!mFillRegion.contains(tilePos))
            mFillRegion = QRegion();
    }

    // Ensure that a fill region was created before making an overlay layer
    if (mFillRegion.isEmpty())
        return;

    // Create a new overlay region
    mFillOverlay = new TileLayer(QString(),
                                 tileLayer->x(),
                                 tileLayer->y(),
                                 tileLayer->width(),
                                 tileLayer->height());

    // Paint the new overlay
    TilePainter tilePainter(mapDocument(), mFillOverlay);
    tilePainter.drawStamp(mStamp, mFillRegion);

    // Crop the overlay to the smallest possible size
    const QRect fillBounds = mFillRegion.boundingRect();
    mFillOverlay->resize(fillBounds.size(), -fillBounds.topLeft());
    mFillOverlay->setX(fillBounds.x());
    mFillOverlay->setY(fillBounds.y());

    // Update the brush item to draw the overlay
    brushItem()->setTileLayer(mFillOverlay);

    // Create connections to know when the overlay should be cleared
    makeConnections();
}
Exemplo n.º 19
0
TileLayer *WangFiller::fillRegion(const TileLayer &back,
                                  const QRegion &fillRegion) const
{
    Q_ASSERT(mWangSet);

    QRect boundingRect = fillRegion.boundingRect();

    TileLayer *tileLayer = new TileLayer(QString(),
                                         boundingRect.x(),
                                         boundingRect.y(),
                                         boundingRect.width(),
                                         boundingRect.height());

    QVector<WangId> wangIds(tileLayer->width() * tileLayer->height(), 0);
    for (const QRect &rect : fillRegion.rects()) {
        for (int x = rect.left(); x <= rect.right(); ++x) {
            int index = x - tileLayer->x() + (rect.top() - tileLayer->y()) * tileLayer->width();
            wangIds[index] = wangIdFromSurroundings(back,
                                                    fillRegion,
                                                    QPoint(x, rect.top()));

            index = x - tileLayer->x() + (rect.bottom() - tileLayer->y())*tileLayer->width();
            wangIds[index] = wangIdFromSurroundings(back,
                                                    fillRegion,
                                                    QPoint(x, rect.bottom()));
        }
        for (int y = rect.top() + 1; y < rect.bottom(); ++y) {
            int index = rect.left() - tileLayer->x() + (y - tileLayer->y())*tileLayer->width();
            wangIds[index] = wangIdFromSurroundings(back,
                                                    fillRegion,
                                                    QPoint(rect.left(), y));

            index = rect.right() - tileLayer->x() + (y - tileLayer->y())*tileLayer->width();
            wangIds[index] = wangIdFromSurroundings(back,
                                                    fillRegion,
                                                    QPoint(rect.right(), y));
        }
    }

    for (const QRect &rect : fillRegion.rects()) {
        for (int y = rect.top(); y <= rect.bottom(); ++y) {
            for (int x = rect.left(); x <= rect.right(); ++x) {
                QPoint currentPoint(x, y);
                int currentIndex = (currentPoint.y() - tileLayer->y()) * tileLayer->width() + (currentPoint.x() - tileLayer->x());

                QList<WangTile> wangTilesList = mWangSet->findMatchingWangTiles(wangIds[currentIndex]);
                RandomPicker<WangTile> wangTiles;

                for (const WangTile &wangTile : wangTilesList)
                    wangTiles.add(wangTile, mWangSet->wangTileProbability(wangTile));

                while (!wangTiles.isEmpty()) {
                    WangTile wangTile = wangTiles.take();

                    bool fill = true;
                    if (!mWangSet->isComplete()) {
                        QPoint adjacentPoints[8];
                        getSurroundingPoints(currentPoint, mStaggeredRenderer, mStaggerAxis, adjacentPoints);

                        for (int i = 0; i < 8; ++i) {
                            QPoint p = adjacentPoints[i];
                            if (!fillRegion.contains(p) || !tileLayer->cellAt(p - tileLayer->position()).isEmpty())
                                continue;
                            p -= tileLayer->position();
                            int index = p.y() * tileLayer->width() + p.x();

                            WangId adjacentWangId = wangIds[index];
                            adjacentWangId.updateToAdjacent(wangTile.wangId(), (i + 4) % 8);

                            if (!mWangSet->wildWangIdIsUsed(adjacentWangId)) {
                                fill = wangTiles.isEmpty();

                                break;
                            }
                        }
                    }

                    if (fill) {
                        tileLayer->setCell(currentPoint.x() - tileLayer->x(),
                                           currentPoint.y() - tileLayer->y(),
                                           wangTile.makeCell());
                        QPoint adjacentPoints[8];
                        getSurroundingPoints(currentPoint, mStaggeredRenderer, mStaggerAxis, adjacentPoints);
                        for (int i = 0; i < 8; ++i) {
                            QPoint p = adjacentPoints[i];
                            if (!fillRegion.contains(p) || !tileLayer->cellAt(p - tileLayer->position()).isEmpty())
                                continue;
                            p -= tileLayer->position();
                            int index = p.y() * tileLayer->width() + p.x();
                            wangIds[index].updateToAdjacent(wangTile.wangId(), (i + 4) % 8);
                        }
                        break;
                    }
                }
            }
        }
    }

    return tileLayer;
}