예제 #1
0
void TilesetDock::updateCurrentTiles()
{
    TilesetView *view = currentTilesetView();
    if (!view)
        return;

    const QItemSelectionModel *s = view->selectionModel();
    if (!s)
        return;

    const QModelIndexList indexes = s->selection().indexes();
    if (indexes.isEmpty())
        return;

    const QModelIndex &first = indexes.first();
    int minX = first.column();
    int maxX = first.column();
    int minY = first.row();
    int maxY = first.row();

    for (const QModelIndex &index : indexes) {
        if (minX > index.column()) minX = index.column();
        if (maxX < index.column()) maxX = index.column();
        if (minY > index.row()) minY = index.row();
        if (maxY < index.row()) maxY = index.row();
    }

    // Create a tile layer from the current selection
    TileLayer *tileLayer = new TileLayer(QString(), 0, 0,
                                         maxX - minX + 1,
                                         maxY - minY + 1);

    const TilesetModel *model = view->tilesetModel();
    for (const QModelIndex &index : indexes) {
        tileLayer->setCell(index.column() - minX,
                           index.row() - minY,
                           Cell(model->tileAt(index)));
    }

    setCurrentTiles(tileLayer);
}
예제 #2
0
파일: tilelayer.cpp 프로젝트: LucasGH/tiled
TileLayer *TileLayer::copy(const QRegion &region) const
{
    const QRegion area = region.intersected(QRect(0, 0, width(), height()));
    const QRect bounds = region.boundingRect();
    const QRect areaBounds = area.boundingRect();
    const int offsetX = qMax(0, areaBounds.x() - bounds.x());
    const int offsetY = qMax(0, areaBounds.y() - bounds.y());

    TileLayer *copied = new TileLayer(QString(),
                                      0, 0,
                                      bounds.width(), bounds.height());

    foreach (const QRect &rect, area.rects())
        for (int x = rect.left(); x <= rect.right(); ++x)
            for (int y = rect.top(); y <= rect.bottom(); ++y)
                copied->setCell(x - areaBounds.x() + offsetX,
                                y - areaBounds.y() + offsetY,
                                cellAt(x, y));

    return copied;
}
예제 #3
0
TileLayer *BucketFillTool::getRandomTileLayer(const QRegion &region) const
{
    QRect bb = region.boundingRect();
    TileLayer *result = new TileLayer(QString(), bb.x(), bb.y(),
                                      bb.width(), bb.height());

    if (region.isEmpty() || mRandomList.empty())
        return result;

    foreach (const QRect &rect, region.rects()) {
        for (int _x = rect.left(); _x <= rect.right(); ++_x) {
            for (int _y = rect.top(); _y <= rect.bottom(); ++_y) {

                result->setCell(_x - bb.x(),
                                _y - bb.y(),
                                mRandomList.at(rand() % mRandomList.size()));
            }
        }
    }
    return result;
}
예제 #4
0
파일: tilelayer.cpp 프로젝트: bjorn/tiled
TileLayer *TileLayer::copy(const QRegion &region) const
{
    const QRect regionBounds = region.boundingRect();
    const QRegion regionWithContents = region.intersected(mBounds);

    TileLayer *copied = new TileLayer(QString(),
                                      0, 0,
                                      regionBounds.width(), regionBounds.height());

#if QT_VERSION < 0x050800
    const auto rects = regionWithContents.rects();
    for (const QRect &rect : rects) {
#else
    for (const QRect &rect : regionWithContents) {
#endif
        for (int x = rect.left(); x <= rect.right(); ++x)
            for (int y = rect.top(); y <= rect.bottom(); ++y)
                copied->setCell(x - regionBounds.x(),
                                y - regionBounds.y(),
                                cellAt(x, y));
    }

    return copied;
}

void TileLayer::merge(const QPoint &pos, const TileLayer *layer)
{
    // Determine the overlapping area
    QRect area = QRect(pos, QSize(layer->width(), layer->height()));
    area &= QRect(0, 0, width(), height());

    for (int y = area.top(); y <= area.bottom(); ++y) {
        for (int x = area.left(); x <= area.right(); ++x) {
            const Cell &cell = layer->cellAt(x - pos.x(),
                                             y - pos.y());
            if (!cell.isEmpty())
                setCell(x, y, cell);
        }
    }
}
예제 #5
0
void TilesetDock::updateCurrentTiles()
{
    const int viewIndex = mViewStack->currentIndex();
    if (viewIndex == -1)
        return;

    const QItemSelectionModel *s = tilesetViewAt(viewIndex)->selectionModel();
    const QModelIndexList indexes = s->selection().indexes();

    if (indexes.isEmpty())
        return;

    const QModelIndex &first = indexes.first();
    int minX = first.column();
    int maxX = first.column();
    int minY = first.row();
    int maxY = first.row();

    foreach (const QModelIndex &index, indexes) {
        if (minX > index.column()) minX = index.column();
        if (maxX < index.column()) maxX = index.column();
        if (minY > index.row()) minY = index.row();
        if (maxY < index.row()) maxY = index.row();
        emit statusInfoChanged(tr("Tile ID:") + QString::number(((TilesetModel*)(s->currentIndex().model()))->tileAt(s->currentIndex())->id()));
    }

    // Create a tile layer from the current selection
    TileLayer *tileLayer = new TileLayer(QString(), 0, 0,
                                         maxX - minX + 1,
                                         maxY - minY + 1);

    const TilesetModel *model = static_cast<const TilesetModel*>(s->model());
    foreach (const QModelIndex &index, indexes) {
        tileLayer->setCell(index.column() - minX,
                           index.row() - minY,
                           Cell(model->tileAt(index)));
    }
예제 #6
0
void TileCollisionDock::setTile(Tile *tile)
{
    if (mTile == tile)
        return;

    mTile = tile;

    mMapScene->disableSelectedTool();
    MapDocument *previousDocument = mDummyMapDocument;

    mMapView->setEnabled(tile);

    if (tile) {
        Map::Orientation orientation = Map::Orthogonal;
        QSize tileSize = tile->size();

        if (tile->tileset()->orientation() == Tileset::Isometric) {
            orientation = Map::Isometric;
            tileSize = tile->tileset()->gridSize();
        }

        Map *map = new Map(orientation, 1, 1, tileSize.width(), tileSize.height());
        map->addTileset(tile->sharedTileset());

        TileLayer *tileLayer = new TileLayer(QString(), 0, 0, 1, 1);
        tileLayer->setCell(0, 0, Cell(tile));
        map->addLayer(tileLayer);

        ObjectGroup *objectGroup;
        if (tile->objectGroup())
            objectGroup = tile->objectGroup()->clone();
        else
            objectGroup = new ObjectGroup;

        objectGroup->setDrawOrder(ObjectGroup::IndexOrder);
        map->setNextObjectId(objectGroup->highestObjectId() + 1);
        map->addLayer(objectGroup);

        mDummyMapDocument = new MapDocument(map);
        mDummyMapDocument->setCurrentLayer(objectGroup);

        mMapScene->setMapDocument(mDummyMapDocument);
        mToolManager->setMapDocument(mDummyMapDocument);

        mMapScene->enableSelectedTool();

        connect(mDummyMapDocument->undoStack(), &QUndoStack::indexChanged,
                this, &TileCollisionDock::applyChanges);

        connect(mDummyMapDocument, &MapDocument::selectedObjectsChanged,
                this, &TileCollisionDock::selectedObjectsChanged);

    } else {
        mDummyMapDocument = nullptr;
        mMapScene->setMapDocument(nullptr);
        mToolManager->setMapDocument(nullptr);
    }

    emit dummyMapDocumentChanged(mDummyMapDocument);

    setHasSelectedObjects(false);

    if (previousDocument) {
        // Explicitly disconnect early from this signal, since it can get fired
        // from the QUndoStack destructor.
        disconnect(previousDocument->undoStack(), &QUndoStack::indexChanged,
                   this, &TileCollisionDock::applyChanges);

        delete previousDocument;
    }
}
예제 #7
0
Tiled::Map *ReplicaIslandPlugin::read(const QString &fileName)
{
    using namespace Tiled;

    // Read data.
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) {
        mError = tr("Cannot open Replica Island map file!");
        return 0;
    }
    QDataStream in(&file);
    in.setByteOrder(QDataStream::LittleEndian);
    in.setFloatingPointPrecision(QDataStream::SinglePrecision);

    // Parse file header.
    quint8 mapSignature, layerCount, backgroundIndex;
    in >> mapSignature >> layerCount >> backgroundIndex;
    if (in.status() == QDataStream::ReadPastEnd || mapSignature != 96) {
        mError = tr("Can't parse file header!");
        return 0;        
    }

    // Create our map, setting width and height to 0 until we load a layer.
    Map *map = new Map(Map::Orthogonal, 0, 0, 32, 32);
    map->setProperty("background_index", QString::number(backgroundIndex));

    // Load our Tilesets.
    QVector<SharedTileset> typeTilesets, tileIndexTilesets;
    loadTilesetsFromResources(map, typeTilesets, tileIndexTilesets);

    // Load each of our layers.
    for (quint8 i = 0; i < layerCount; i++) {
        // Parse layer header.
        quint8 type, tileIndex, levelSignature;
        float scrollSpeed;
        qint32 width, height;
        in >> type >> tileIndex >> scrollSpeed
           >> levelSignature >> width >> height;
        if (in.status() == QDataStream::ReadPastEnd || levelSignature != 42) {
            delete map;
            mError = tr("Can't parse layer header!");
            return 0;        
        }

        // Make sure our width and height are consistent.
        if (map->width() == 0)
            map->setWidth(width);
        if (map->height() == 0)
            map->setHeight(height);
        if (map->width() != width || map->height() != height) {
            delete map;
            mError = tr("Inconsistent layer sizes!");
            return 0;
        }

        // Create a layer object.
        TileLayer *layer =
            new TileLayer(layerTypeToName(type), 0, 0, width, height);
        layer->setProperty("type", QString::number(type));
        layer->setProperty("tile_index", QString::number(tileIndex));
        layer->setProperty("scroll_speed", QString::number(scrollSpeed, 'f'));
        map->addLayer(layer);

        // Look up the tileset for this layer.
        SharedTileset tileset =
            tilesetForLayer(type, tileIndex, typeTilesets, tileIndexTilesets);

        // Read our tile data all at once.
        QByteArray tileData(width*height, '\0');
        int bytesRead = in.readRawData(tileData.data(), tileData.size());
        if (bytesRead != tileData.size()) {
            delete map;
            mError = tr("File ended in middle of layer!");
            return 0;            
        }
        quint8 *tp = reinterpret_cast<quint8 *>(tileData.data());

        // Add the tiles to our layer.
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                quint8 tile_id = *tp++;
                if (tile_id != 255) {
                    Tile *tile = tileset->findTile(tile_id);
                    layer->setCell(x, y, Cell(tile));
                }
            }
        }
    }

    // Make sure we read the entire *.bin file.
    if (in.status() != QDataStream::Ok || !in.atEnd()) {
        delete map;
        mError = tr("Unexpected data at end of file!");
        return 0;        
    }

    return map;
}
예제 #8
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;
}
예제 #9
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;
}