Example #1
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()) {
        const QRect mapRect(QPoint(), variation.map->size());
        QSize rotatedSize;

        for (auto layer : variation.map->tileLayers()) {
            TileLayer *tileLayer = static_cast<TileLayer*>(layer);

            // Synchronize tile layer size to map size (assumes map contains all layers)
            if (tileLayer->rect() != mapRect) {
                tileLayer->resize(mapRect.size(), tileLayer->position());
                tileLayer->setPosition(0, 0);
            }

            if (variation.map->orientation() == Map::Hexagonal)
                tileLayer->rotateHexagonal(direction, variation.map);
            else
                tileLayer->rotate(direction);

            rotatedSize = tileLayer->size();
        }

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

    return rotated;
}
Example #2
0
void BucketFillTool::randomFill(TileLayer &tileLayer, const QRegion &region) const
{
    if (region.isEmpty() || mRandomCellPicker.isEmpty())
        return;

    for (const QRect &rect : region.translated(-tileLayer.position()).rects()) {
        for (int _x = rect.left(); _x <= rect.right(); ++_x) {
            for (int _y = rect.top(); _y <= rect.bottom(); ++_y) {
                tileLayer.setCell(_x, _y,
                                  mRandomCellPicker.pick());
            }
        }
    }
}
Example #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()) {
        const QRect mapRect(QPoint(), variation.map->size());

        for (auto layer : variation.map->tileLayers()) {
            TileLayer *tileLayer = static_cast<TileLayer*>(layer);

            // Synchronize tile layer size to map size (assumes map contains all layers)
            if (tileLayer->rect() != mapRect) {
                tileLayer->resize(mapRect.size(), tileLayer->position());
                tileLayer->setPosition(0, 0);
            }

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

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

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

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

    return flipped;
}
Example #4
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;
}
Example #5
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;
}
Example #6
0
void AbstractTileFillTool::randomFill(TileLayer &tileLayer, const QRegion &region) const
{
    if (region.isEmpty() || mRandomCellPicker.isEmpty())
        return;

    const auto localRegion = region.translated(-tileLayer.position());

#if QT_VERSION < 0x050800
    const auto rects = localRegion.rects();
    for (const QRect &rect : rects) {
#else
    for (const QRect &rect : localRegion) {
#endif
        for (int y = rect.top(); y <= rect.bottom(); ++y) {
            for (int x = rect.left(); x <= rect.right(); ++x) {
                tileLayer.setCell(x, y,
                                  mRandomCellPicker.pick());
            }
        }
    }
}

void AbstractTileFillTool::wangFill(TileLayer &tileLayerToFill,
                                    const TileLayer &backgroundTileLayer,
                                    const QRegion &region) const
{
    if (!mWangSet)
        return;

    WangFiller wangFiller(mWangSet,
                          dynamic_cast<StaggeredRenderer *>(mapDocument()->renderer()),
                          mapDocument()->map()->staggerAxis());

    auto stamp = wangFiller.fillRegion(backgroundTileLayer, region);
    tileLayerToFill.setCells(0, 0, stamp.get());
}

void AbstractTileFillTool::fillWithStamp(Map &map,
                                         const TileStamp &stamp,
                                         const QRegion &mask)
{
    if (stamp.isEmpty())
        return;

    const QSize size = stamp.maxSize();
    if (size.isEmpty())
        return;

    const QRect bounds = mask.boundingRect();

    // Fill the entire map with random variations of the stamp
    for (int y = 0; y < bounds.height(); y += size.height()) {
        for (int x = 0; x < bounds.width(); x += size.width()) {
            const Map *stampMap = stamp.randomVariation().map;

            for (Layer *layer : stampMap->tileLayers()) {
                TileLayer *target = static_cast<TileLayer*>(map.findLayer(layer->name(), Layer::TileLayerType));
                if (!target) {
                    target = new TileLayer(layer->name(), bounds.topLeft(), bounds.size());
                    map.addLayer(target);
                }
                target->setCells(x, y, static_cast<TileLayer*>(layer));
            }
        }
    }

    // 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.
    for (Layer *layer : map.tileLayers()) {
        auto tileLayer = static_cast<TileLayer*>(layer);
        tileLayer->erase((QRegion(tileLayer->bounds()) - mask).translated(-tileLayer->position()));
    }
}

void AbstractTileFillTool::invalidateRandomAndMissingCache()
{
    mRandomAndMissingCacheValid = false;
}