void TransitionTerrain::addTransitionOnMap(Tiled::Map &tiledMap)
{
    const unsigned int w=tiledMap.width();
    const unsigned int h=tiledMap.height();

    //list the layer name to parse
    QHash<QString,LoadMap::Terrain> transition;
    QStringList transitionList;
    for(int height=0;height<5;height++)
        for(int moisure=0;moisure<6;moisure++)
        {
            LoadMap::Terrain &terrain=LoadMap::terrainList[height][moisure];
            if(!terrain.tmp_layerString.isEmpty())
            {
                if(!transitionList.contains(terrain.terrainName))
                {
                    transition[terrain.terrainName]=terrain;
                    transitionList << terrain.terrainName;
                }
            }
        }

    {
        Tiled::TileLayer * transitionLayerMask=LoadMap::searchTileLayerByName(tiledMap,"OnGrass");
        Tiled::TileLayer * const colisionLayerMask=LoadMap::searchTileLayerByName(tiledMap,"Collisions");
        unsigned int index=0;
        while(index<(unsigned int)transitionList.size())
        {
            const LoadMap::Terrain &terrain=transition.value(transitionList.at(index));
            Tiled::TileLayer * terrainLayer=terrain.tileLayer;
            Tiled::TileLayer * transitionLayer=NULL;
            uint16_t XORop;
            if(terrain.outsideBorder)
            {
                transitionLayer=terrainLayer;
                XORop=0x01ff;
            }
            else
            {
                const unsigned int index=LoadMap::searchTileIndexByName(tiledMap,terrain.tmp_layerString);
                Tiled::Layer * rawLayer=tiledMap.layerAt(index+1);
                if(!rawLayer->isTileLayer())
                {
                    std::cerr << "Next layer after " << terrain.tmp_layerString.toStdString() << "is not tile layer (abort)" << std::endl;
                    abort();
                }
                transitionLayer=static_cast<Tiled::TileLayer *>(rawLayer);
                transitionLayerMask=transitionLayer;
                XORop=0x0000;
            }
            unsigned int y=0;
            while(y<h)
            {
                unsigned int x=0;
                while(x<w)
                {
                    const bool innerBool=!XORop && (terrainLayer->cellAt(x,y).tile==terrain.tile);
                    const unsigned int &bitMask=x+y*w;
                    const bool outerBool=XORop && terrainLayer->cellAt(x,y).tile!=terrain.tile && !(MapBrush::mapMask[bitMask/8] & (1<<(7-bitMask%8)));
                    if(
                            //inner
                            innerBool ||
                            //outer
                            outerBool
                            )
                    {
                        //check the near tile and determine what transition use
                        const uint16_t to_type_match=layerMask(terrainLayer,x,y,terrain.tile,XORop);
                        if(to_type_match>512)
                            abort();

                        if(to_type_match!=0 && to_type_match!=16)
                        {
                            unsigned int indexTile=0;
                            if(XORop)
                            {
                                const uint16_t to_type_match_collision=layerMask(colisionLayerMask,x,y,NULL,false);
                                const bool onGrass=transitionLayerMask->cellAt(x,y).tile!=NULL;
                                bool forceDisplay=false;
                                //outer border
                                if(to_type_match&2)
                                {
                                    if(to_type_match&8)
                                    {
                                        indexTile=8;
                                    }
                                    else if(to_type_match&32)
                                    {
                                        indexTile=9;
                                    }
                                    else
                                    {
                                        indexTile=5;
                                        if(to_type_match_collision&8 && to_type_match_collision&32)
                                            forceDisplay=true;
                                    }
                                }
                                else if(to_type_match&128)
                                {
                                    if(to_type_match&8)
                                    {
                                        indexTile=11;
                                    }
                                    else if(to_type_match&32)
                                    {
                                        indexTile=10;
                                    }
                                    else
                                    {
                                        indexTile=1;
                                        if(to_type_match_collision&8 && to_type_match_collision&32)
                                            forceDisplay=true;
                                    }
                                }
                                else if(to_type_match&8)
                                {
                                    indexTile=3;
                                    if(to_type_match_collision&2 && to_type_match_collision&128)
                                        forceDisplay=true;
                                }
                                else if(to_type_match&32)
                                {
                                    indexTile=7;
                                    if(to_type_match_collision&2 && to_type_match_collision&128)
                                        forceDisplay=true;
                                }
                                else if(to_type_match&256)
                                {
                                    indexTile=0;
                                    if(!(to_type_match_collision&256))
                                    {
                                        if(to_type_match_collision&32 && to_type_match_collision&128)
                                            forceDisplay=true;
                                        if(to_type_match_collision&8 && to_type_match_collision&32)
                                            forceDisplay=true;
                                        if(to_type_match_collision&2 && to_type_match_collision&128)
                                            forceDisplay=true;
                                    }
                                }
                                else if(to_type_match&64)
                                {
                                    indexTile=2;
                                    if(!(to_type_match_collision&64))
                                    {
                                        if(to_type_match_collision&8 && to_type_match_collision&128)
                                            forceDisplay=true;
                                        if(to_type_match_collision&8 && to_type_match_collision&32)
                                            forceDisplay=true;
                                        if(to_type_match_collision&2 && to_type_match_collision&128)
                                            forceDisplay=true;
                                    }
                                }
                                else if(to_type_match&1)
                                {
                                    indexTile=4;
                                    if(!(to_type_match_collision&1))
                                    {
                                        if(to_type_match_collision&2 && to_type_match_collision&8)
                                            forceDisplay=true;
                                        if(to_type_match_collision&8 && to_type_match_collision&32)
                                            forceDisplay=true;
                                        if(to_type_match_collision&2 && to_type_match_collision&128)
                                            forceDisplay=true;
                                    }
                                }
                                else if(to_type_match&4)
                                {
                                    indexTile=6;
                                    if(!(to_type_match_collision&4))
                                    {
                                        if(to_type_match_collision&2 && to_type_match_collision&32)
                                            forceDisplay=true;
                                        if(to_type_match_collision&8 && to_type_match_collision&32)
                                            forceDisplay=true;
                                        if(to_type_match_collision&2 && to_type_match_collision&128)
                                            forceDisplay=true;
                                    }
                                }

                                if(!onGrass || forceDisplay)
                                {
                                    Tiled::Cell cell;
                                    cell.tile=terrain.transition_tile.at(indexTile);
                                    cell.flippedHorizontally=false;
                                    cell.flippedVertically=false;
                                    cell.flippedAntiDiagonally=false;
                                    transitionLayer->setCell(x,y,cell);
                                }
                            }
                            else
                            {
                                //inner border
                                if(to_type_match&2)
                                {
                                    if(to_type_match&8)
                                        indexTile=0;
                                    else if(to_type_match&32)
                                        indexTile=2;
                                    else
                                        indexTile=1;
                                }
                                else if(to_type_match&128)
                                {
                                    if(to_type_match&8)
                                        indexTile=6;
                                    else if(to_type_match&32)
                                        indexTile=4;
                                    else
                                        indexTile=5;
                                }
                                else if(to_type_match&8)
                                    indexTile=7;
                                else if(to_type_match&32)
                                    indexTile=3;
                                else if(to_type_match&256)
                                    indexTile=8;
                                else if(to_type_match&64)
                                    indexTile=9;
                                else if(to_type_match&1)
                                    indexTile=10;
                                else if(to_type_match&4)
                                    indexTile=11;

                                Tiled::Cell cell;
                                cell.tile=terrain.transition_tile.at(indexTile);
                                cell.flippedHorizontally=false;
                                cell.flippedVertically=false;
                                cell.flippedAntiDiagonally=false;
                                transitionLayer->setCell(x,y,cell);
                            }
                        }
                    }
                    x++;
                }
                y++;
            }
            index++;
        }
    }
}
Example #2
0
/**
 * Implements Tiled::MapReaderInterface
 */
Tiled::Map *PythonPlugin::read(const QString &fileName)
{
    reloadModules();

    QMapIterator<QString, PyObject*> it(mKnownExtClasses);
    while (it.hasNext()) {
        it.next();
        if (!checkFileSupport(it.value(), fileName.toUtf8().data()))
            continue;
        log(QString("-- %1 supports %2\n").arg(it.key()).arg(fileName));

        if (!PyObject_HasAttrString(it.value(), "read")) {
            mError = "Please define class that extends tiled.Plugin and "
                    "has @classmethod read(cls, filename)";
            return NULL;
        }
        PyObject *pinst = PyObject_CallMethod(it.value(), (char *)"read",
                                              (char *)"(s)", fileName.toUtf8().data());

        Tiled::Map *ret = 0;
        if (!pinst) {
            PySys_WriteStderr("** Uncaught exception in script **\n");
        } else {
            _wrap_convert_py2c__Tiled__Map___star__(pinst, &ret);
            Py_DECREF(pinst);
        }
        handleError();

        if (ret)
            ret->setProperty("__script__", it.key());
        return ret;
    }
    return NULL;
}
Example #3
0
bool TiledMap::load()
{
    Tiled::Map *tiledMap;
    Tiled::MapReader reader;

    tiledMap = reader.readMap(m_mapSource);

    if (!tiledMap) {
        qCritical() << "Fail to read map " << m_mapSource;
        return false;
    }

    if (tiledMap->orientation() == Tiled::Map::Isometric) {
        setRenderer(new TiledRenderer(new Tiled::IsometricRenderer(tiledMap), this));
    } else if (tiledMap->orientation() == Tiled::Map::Orthogonal) {
        setRenderer(new TiledRenderer(new Tiled::OrthogonalRenderer(tiledMap), this));
    } else {
        qWarning() << "Map type not supported.";
        return false;
    }

    setTiledMap(tiledMap);

    loadLayers(tiledMap);

    emit loaded();

    return true;
}
Example #4
0
Tiled::Map *PythonMapFormat::read(const QString &fileName)
{
    mError = QString();

    mPlugin.log(tr("-- Using script %1 to read %2").arg(mScriptFile, fileName));

    if (!PyObject_HasAttrString(mClass, "read")) {
        mError = "Please define class that extends tiled.Plugin and "
                "has @classmethod read(cls, filename)";
        return nullptr;
    }
    PyObject *pinst = PyObject_CallMethod(mClass, (char *)"read",
                                          (char *)"(s)", fileName.toUtf8().constData());

    Tiled::Map *ret = nullptr;
    if (!pinst) {
        PySys_WriteStderr("** Uncaught exception in script **\n");
    } else {
        _wrap_convert_py2c__Tiled__Map___star__(pinst, &ret);
        Py_DECREF(pinst);
    }
    handleError();

    if (ret)
        ret->setProperty("__script__", mScriptFile);
    return ret;
}
void TransitionTerrain::changeTileLayerOrder(Tiled::Map &tiledMap)
{
    const int indexOfLayerWalkable=tiledMap.indexOfLayer("Walkable");
    if(indexOfLayerWalkable<0)
        return;
    const int indexOfLayerGrass=tiledMap.indexOfLayer("Grass");
    if(indexOfLayerGrass<0)
        return;
    Tiled::Layer *layerZoneGrass=tiledMap.takeLayerAt(indexOfLayerGrass);
    tiledMap.insertLayer(indexOfLayerWalkable+1,layerZoneGrass);
}
Example #6
0
/* -------------------------------------------------------------------------------------------
 *
 * ------------------------------------------------------------------------------------------- */
void DMWindow::addMap() {
  QString fileName = QFileDialog::getOpenFileName(this,tr("Open Game"),rpg::FileUtils::mapsDirectory(), tr("Map Files (*.tmx)"));
  if(fileName  != "") {
    // Get the name of the map
    Tiled::MapReader reader;
    Tiled::Map *map = reader.readMap(fileName);
    QString name = map->properties()["name"] == "" ? QDir(fileName).dirName() : map->properties()["name"];
    delete map;

    QVariantMap data;
    data.insert("name", name);
    data.insert("file",rpg::FileUtils::relativeTo(rpg::FileUtils::mapsDirectory(), fileName));
    this->engine->getRepository()->put("maps",QUuid::createUuid().toString(),data);
    this->updateMapList();
  }
}
Example #7
0
int main(int argc, char *argv[])
{
    /*
     * On X11, Tiled uses the 'raster' graphics system by default, because the
     * X11 native graphics system has performance problems with drawing the
     * tile grid.
     */
#ifdef Q_WS_X11
    QApplication::setGraphicsSystem(QLatin1String("raster"));
#endif

    TiledApplication a(argc, argv);

    a.setOrganizationDomain(QLatin1String("mapeditor.org"));
    a.setApplicationName(QLatin1String("Tiled - Sydoria Map Editor"));
#ifdef BUILD_INFO_VERSION
    a.setApplicationVersion(QLatin1String(AS_STRING(BUILD_INFO_VERSION)));
#else
    a.setApplicationVersion(QLatin1String("0.11.0"));
#endif

#ifdef Q_OS_MAC
    a.setAttribute(Qt::AA_DontShowIconsInMenus);
#endif

#if QT_VERSION >= 0x050100
    // Enable support for highres images (added in Qt 5.1, but off by default)
    a.setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif

#ifndef Q_OS_WIN
    QString baseName = QApplication::style()->objectName();
    if (baseName == QLatin1String("windows")) {
        // Avoid Windows 95 style at all cost
        if (QStyleFactory::keys().contains(QLatin1String("Fusion"))) {
            baseName = QLatin1String("fusion"); // Qt5
        } else { // Qt4
            // e.g. if we are running on a KDE4 desktop
            QByteArray desktopEnvironment = qgetenv("DESKTOP_SESSION");
            if (desktopEnvironment == "kde")
                baseName = QLatin1String("plastique");
            else
                baseName = QLatin1String("cleanlooks");
        }
        a.setStyle(QStyleFactory::create(baseName));
    }
#endif

    LanguageManager *languageManager = LanguageManager::instance();
    languageManager->installTranslators();

    CommandLineHandler commandLine;

    if (!commandLine.parse(QCoreApplication::arguments()))
        return 0;
    if (commandLine.quit)
        return 0;
    if (commandLine.disableOpenGL)
        Preferences::instance()->setUseOpenGL(false);

    PluginManager::instance()->loadPlugins();

    if (commandLine.exportMap) {
        // Get the path to the source file and target file
        if (commandLine.filesToOpen().length() < 2) {
            qWarning() << qPrintable(QCoreApplication::translate("Command line",
                                                                 "Export syntax is --export-map [format] <tmx file> <target file>"));
            return 1;
        }
        int index = 0;
        const QString *filter = commandLine.filesToOpen().length() > 2 ? &commandLine.filesToOpen().at(index++) : 0;
        const QString &sourceFile = commandLine.filesToOpen().at(index++);
        const QString &targetFile = commandLine.filesToOpen().at(index++);

        // Find the map writer interface for the target file
        Tiled::MapWriterInterface *chosenWriter = 0;
        QString suffix = QFileInfo(targetFile).completeSuffix();
        QList<Tiled::MapWriterInterface*> writers = PluginManager::instance()->interfaces<Tiled::MapWriterInterface>();
        foreach (Tiled::MapWriterInterface *writer, writers) {
            if (filter) {
                if (writer->nameFilters().contains(*filter, Qt::CaseInsensitive)) {
                    chosenWriter = writer;
                }
            }
            else if (!writer->nameFilters().filter(suffix, Qt::CaseInsensitive).isEmpty()) {
                if (chosenWriter) {
                    qWarning() << qPrintable(QCoreApplication::translate("Command line",
                                                                         "Non-unique file extension. Can't determine correct export format."));
                    return 1;
                }
                chosenWriter = writer;
            }
        }
        if (!chosenWriter) {
            qWarning() << qPrintable(QCoreApplication::translate("Command line",
                                                                 "No exporter found for target file."));
            return 1;
        }

        // Load the source file
        Tiled::MapReader reader;
        Tiled::Map *map = reader.readMap(sourceFile);
        if (!map) {
            qWarning() << qPrintable(QCoreApplication::translate("Command line",
                                                                 "Failed to load source map."));
            return 1;
        }

        // Write out the file
        bool success = chosenWriter->write(map, targetFile);

        qDeleteAll(map->tilesets());
        delete map;

        if (!success) {
            qWarning() << qPrintable(QCoreApplication::translate("Command line",
                                                                 "Failed to export map to target file."));
            return 1;
        }
        return 0;
    }

    MainWindow w;
    w.show();

    QObject::connect(&a, SIGNAL(fileOpenRequest(QString)),
                     &w, SLOT(openFile(QString)));

    if (!commandLine.filesToOpen().isEmpty()) {
        foreach (const QString &fileName, commandLine.filesToOpen())
            w.openFile(fileName);
    } else {
Example #8
0
void MainWindow::updateSavegameList()
{
    if(!datapackPathExists)
    {
        ui->savegameEmpty->setText(QString("<html><head/><body><p align=\"center\"><span style=\"font-size:12pt;color:#a0a0a0;\">%1</span></p></body></html>").arg(tr("No datapack!")));
        return;
    }
    QString lastSelectedPath;
    if(selectedSavegame!=NULL)
        lastSelectedPath=savegamePathList[selectedSavegame];
    selectedSavegame=NULL;
    int index=0;
    while(savegame.size()>0)
    {
        delete savegame.at(0);
        savegame.removeAt(0);
        index++;
    }
    savegamePathList.clear();
    savegameWithMetaData.clear();
    QFileInfoList entryList=QDir(savegamePath).entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Hidden|QDir::System,QDir::DirsFirst);//possible wait time here
    index=0;
    while(index<entryList.size())
    {
        bool ok=false;
        QFileInfo fileInfo=entryList.at(index);
        if(!fileInfo.isDir())
        {
            index++;
            continue;
        }
        QString savegamesPath=fileInfo.absoluteFilePath()+"/";
        QSettings metaData(savegamesPath+"metadata.conf",QSettings::IniFormat);
        SaveGameLabel *newEntry=new SaveGameLabel();
        connect(newEntry,SIGNAL(clicked()),this,SLOT(savegameLabelClicked()),Qt::QueuedConnection);
        connect(newEntry,SIGNAL(doubleClicked()),this,SLOT(savegameLabelDoubleClicked()),Qt::QueuedConnection);
        newEntry->setStyleSheet("QLabel::hover{border:1px solid #bbb;background-color:rgb(180,180,180,100);border-radius:10px;}");
        QString dateString;
        if(!QFileInfo(savegamesPath+"metadata.conf").exists())
            newEntry->setText(QString("<span style=\"font-size:12pt;font-weight:600;\">Missing metadata</span><br/><span style=\"color:#909090;\">Missing metadata<br/>Bug</span>"));
        else
        {
            dateString=QFileInfo(savegamesPath+"metadata.conf").lastModified().toString("dd/MM/yyyy hh:mm:ssAP");
            if(!metaData.isWritable())
                newEntry->setText(QString("<span style=\"font-size:12pt;font-weight:600;\">%1</span><br/><span style=\"color:#909090;\">%2<br/>Bug</span>").arg("Bug").arg(dateString));
            else
            {
                if(metaData.status()==QSettings::NoError)
                {
                    if(metaData.contains("title") && metaData.contains("location") && metaData.contains("time_played") && metaData.contains("pass"))
                    {
                        int time_played_number=metaData.value("time_played").toUInt(&ok);
                        QString time_played;
                        if(!ok)
                            time_played="Time player: bug";
                        else if(time_played_number>=3600*24*10)
                            time_played=QObject::tr("%n day(s) played","",time_played_number/(3600*24));
                        else if(time_played_number>=3600*24)
                            time_played=QObject::tr("%n day(s) and %1 played","",time_played_number/3600*24).arg(QObject::tr("%n hour(s)","",(time_played_number%(3600*24))/3600));
                        else if(time_played_number>=3600)
                            time_played=QObject::tr("%n hour(s) and %1 played","",time_played_number/3600).arg(QObject::tr("%n minute(s)","",(time_played_number%3600)/60));
                        else
                            time_played=QObject::tr("%n minute(s) and %1 played","",time_played_number/60).arg(QObject::tr("%n second(s)","",time_played_number%60));

                        //load the map name
                        QString mapName=metaData.value("location").toString();
                        Tiled::MapReader reader;
                        Tiled::Map * tiledMap = reader.readMap(datapackPath+DATAPACK_BASE_PATH_MAP+metaData.value("location").toString());
                        if(tiledMap)
                        {
                            if(tiledMap->properties().contains("name"))
                                mapName=tiledMap->properties().value("name");
                            delete tiledMap;
                        }

                        newEntry->setText(QString("<span style=\"font-size:12pt;font-weight:600;\">%1</span><br/><span style=\"color:#909090;\">%2<br/>%3 (%4)</span>")
                                          .arg(metaData.value("title").toString())
                                          .arg(dateString)
                                          .arg(mapName)
                                          .arg(time_played)
                                          );
                    }
                }
                else
                    newEntry->setText(QString("<span style=\"font-size:12pt;font-weight:600;\">%1</span><br/><span style=\"color:#909090;\">%2<br/>Bug</span>").arg(metaData.value("title").toString()).arg(dateString));
            }
        }
        ui->scrollAreaWidgetContents->layout()->addWidget(newEntry);

        if(lastSelectedPath==savegamesPath)
            selectedSavegame=newEntry;
        savegame << newEntry;
        savegamePathList[newEntry]=savegamesPath;
        savegameWithMetaData[newEntry]=ok;
        index++;
    }
    ui->savegameEmpty->setVisible(index==0);
    if(index>0)
    {
        ui->scrollAreaWidgetContents->layout()->removeItem(spacer);
        delete spacer;
        spacer=new QSpacerItem(0,0,QSizePolicy::Expanding,QSizePolicy::Expanding);
        ui->scrollAreaWidgetContents->layout()->addItem(spacer);
    }
    savegameLabelUpdate();
}
Example #9
0
Tiled::Map *TbinMapFormat::read(const QString &fileName)
{
    std::ifstream file( fileName.toStdString(), std::ios::in | std::ios::binary );
    if (!file) {
        mError = tr("Could not open file for reading.");
        return nullptr;
    }

    tbin::Map tmap;
    Tiled::Map* map = nullptr;
    try
    {
        tmap.loadFromStream(file);
        map = new Tiled::Map(Tiled::Map::Orthogonal, tmap.layers[0].layerSize.x, tmap.layers[0].layerSize.y, tmap.layers[0].tileSize.x, tmap.layers[0].tileSize.y);
        tbinToTiledProperties(tmap.props, map);

        const QDir fileDir(QFileInfo(fileName).dir());

        std::map< std::string, int > tmapTilesheetMapping;
        for (std::size_t i = 0; i < tmap.tilesheets.size(); ++i) {
            const tbin::TileSheet& ttilesheet = tmap.tilesheets[i];
            tmapTilesheetMapping[ttilesheet.id] = i;

            if (ttilesheet.spacing.x != ttilesheet.spacing.y)
                throw std::invalid_argument(QT_TR_NOOP("Tilesheet must have equal spacings."));
            if (ttilesheet.margin.x != ttilesheet.margin.y)
                throw std::invalid_argument(QT_TR_NOOP("Tilesheet must have equal margins."));

            auto tilesheet = Tiled::Tileset::create(ttilesheet.id.c_str(), ttilesheet.tileSize.x, ttilesheet.tileSize.y, ttilesheet.spacing.x, ttilesheet.margin.x);
            tilesheet->setImageSource(Tiled::toUrl(QString::fromStdString(ttilesheet.image), fileDir));
            if (!tilesheet->loadImage()) {
                QList<Tiled::Tile*> tiles;
                for (int i = 0; i < ttilesheet.sheetSize.x * ttilesheet.sheetSize.y; ++i) {
                    tiles.append(new Tiled::Tile(i, tilesheet.data()));
                }
                tilesheet->addTiles(tiles);
            }
            tbinToTiledProperties(ttilesheet.props, tilesheet.data());

            for (auto prop : ttilesheet.props) {
                if (prop.first[0] != '@')
                    continue;

                QStringList strs = QString(prop.first.c_str()).split('@');
                if (strs[1] == "TileIndex") {
                    int index = strs[2].toInt();
                    tbin::Properties dummyProps;
                    dummyProps.insert(std::make_pair(strs[3].toStdString(), prop.second));
                    Tiled::Tile* tile = tilesheet->tileAt(index);
                    tbinToTiledProperties(dummyProps, tile);
                }
                // TODO: 'AutoTile' ?
                // Purely for map making. Appears to be similar to terrains
                // (In tIDE, right click a tilesheet and choose "Auto Tiles..."
            }

            map->addTileset(tilesheet);
        }
        for (const tbin::Layer& tlayer : tmap.layers) {
            if (tlayer.tileSize.x != tmap.layers[0].tileSize.x || tlayer.tileSize.y != tmap.layers[0].tileSize.y)
                throw std::invalid_argument(QT_TR_NOOP("Different tile sizes per layer are not supported."));

            QScopedPointer<Tiled::TileLayer> layer(new Tiled::TileLayer(tlayer.id.c_str(), 0, 0, tlayer.layerSize.x, tlayer.layerSize.y));
            tbinToTiledProperties(tlayer.props, layer.data());
            QScopedPointer<Tiled::ObjectGroup> objects(new Tiled::ObjectGroup(tlayer.id.c_str(), 0, 0));
            for (std::size_t i = 0; i < tlayer.tiles.size(); ++i) {
                const tbin::Tile& ttile = tlayer.tiles[i];
                int ix = i % tlayer.layerSize.x;
                int iy = i / tlayer.layerSize.x;

                if (ttile.isNullTile())
                    continue;

                Tiled::Cell cell;
                if (ttile.animatedData.frames.size() > 0) {
                    tbin::Tile tfirstTile = ttile.animatedData.frames[0];
                    Tiled::Tile* firstTile = map->tilesetAt(tmapTilesheetMapping[tfirstTile.tilesheet])->tileAt(tfirstTile.staticData.tileIndex);
                    QVector<Tiled::Frame> frames;
                    for (const tbin::Tile& tframe : ttile.animatedData.frames) {
                        if (tframe.isNullTile() || tframe.animatedData.frames.size() > 0 ||
                             tframe.tilesheet != tfirstTile.tilesheet)
                            throw std::invalid_argument(QT_TR_NOOP("Invalid animation frame."));

                        Tiled::Frame frame;
                        frame.tileId = tframe.staticData.tileIndex;
                        frame.duration = ttile.animatedData.frameInterval;
                        frames.append(frame);
                    }
                    firstTile->setFrames(frames);
                    cell = Tiled::Cell(firstTile);
                }
                else {
                    cell = Tiled::Cell(map->tilesetAt(tmapTilesheetMapping[ttile.tilesheet])->tileAt(ttile.staticData.tileIndex));
                }
                layer->setCell(ix, iy, cell);

                if (ttile.props.size() > 0) {
                    Tiled::MapObject* obj = new Tiled::MapObject("TileData", QString(), QPointF(ix * tlayer.tileSize.x, iy * tlayer.tileSize.y), QSizeF(tlayer.tileSize.x, tlayer.tileSize.y));
                    tbinToTiledProperties(ttile.props, obj);
                    objects->addObject(obj);
                }
            }
            map->addLayer(layer.take());
            map->addLayer(objects.take());
        }
    }
    catch (std::exception& e) {
        mError = tr((std::string("Exception: ") + e.what()).c_str());
    }

    return map;
}
void TransitionTerrain::addTransitionGroupOnMap(Tiled::Map &tiledMap)
{
    const unsigned int w=tiledMap.width();
    const unsigned int h=tiledMap.height();

    //list the layer name to parse
    QHash<QString,LoadMap::Terrain> transition;
    QStringList transitionList;
    for(int height=0;height<5;height++)
        for(int moisure=0;moisure<6;moisure++)
        {
            LoadMap::Terrain &terrain=LoadMap::terrainList[height][moisure];
            if(!terrain.tmp_layerString.isEmpty())
            {
                if(!transitionList.contains(terrain.terrainName))
                {
                    transition[terrain.terrainName]=terrain;
                    transitionList << terrain.terrainName;
                }
            }
        }

    //outer border
    {
        unsigned int index=0;
        while(index<(unsigned int)LoadMap::groupedTerrainList.size())
        {
            const LoadMap::GroupedTerrain &groupedTerrain=LoadMap::groupedTerrainList.at(index);
            Tiled::TileLayer * transitionLayer=groupedTerrain.tileLayer;
            unsigned int y=0;
            while(y<h)
            {
                unsigned int x=0;
                while(x<w)
                {
                    const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x+y*w].index);
                    const unsigned int &bitMask=x+y*w;
                    if(!(MapBrush::mapMask[bitMask/8] & (1<<(7-bitMask%8))))
                    {
                        if(zone.height<groupedTerrain.height)
                        {
                            //check the near tile and determine what transition use
                            uint8_t to_type_match=0;//9 bits used-1=8bit, the center bit is the current tile
                            if(x>0 && y>0)
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x-1+(y-1)*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=1;
                            }
                            if(y>0)
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x+(y-1)*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=2;
                            }
                            if(x<(w-1) && y>0)
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x+1+(y-1)*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=4;
                            }
                            if(x>0)
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x-1+y*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=8;
                            }
                            if(x<(w-1))
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x+1+y*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=16;
                            }
                            if(x>0 && y<(h-1))
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x-1+(y+1)*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=32;
                            }
                            if(y<(h-1))
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x+(y+1)*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=64;
                            }
                            if(x<(w-1) && y<(h-1))
                            {
                                const vd::PolygonZone &zone=vd::voronoiMap.zones.at(vd::voronoiMap.tileToPolygonZoneIndex[x+1+(y+1)*w].index);
                                if(zone.height>=groupedTerrain.height)
                                    to_type_match|=128;
                            }

                            if(to_type_match!=0)
                            {
                                unsigned int indexTile=0;

                                if(to_type_match&2)
                                {
                                    if(to_type_match&8)
                                        indexTile=8;
                                    else if(to_type_match&16)
                                        indexTile=9;
                                    else
                                        indexTile=5;
                                }
                                else if(to_type_match&64)
                                {
                                    if(to_type_match&8)
                                        indexTile=11;
                                    else if(to_type_match&16)
                                        indexTile=10;
                                    else
                                        indexTile=1;
                                }
                                else if(to_type_match&8)
                                    indexTile=3;
                                else if(to_type_match&16)
                                    indexTile=7;
                                else if(to_type_match&128)
                                    indexTile=0;
                                else if(to_type_match&32)
                                    indexTile=2;
                                else if(to_type_match&1)
                                    indexTile=4;
                                else if(to_type_match&4)
                                    indexTile=6;

                                Tiled::Cell cell;
                                cell.tile=groupedTerrain.transition_tile.at(indexTile);
                                cell.flippedHorizontally=false;
                                cell.flippedVertically=false;
                                cell.flippedAntiDiagonally=false;
                                transitionLayer->setCell(x,y,cell);
                            }
                        }
                    }
                    x++;
                }
                y++;
            }
            index++;
        }
    }
}
void TransitionTerrain::mergeDown(Tiled::Map &tiledMap)
{
    const unsigned int w=tiledMap.width();
    const unsigned int h=tiledMap.height();

    std::vector<Tiled::TileLayer *> layerToDelete;
    unsigned int terrainIndex=0;
    while(terrainIndex<(unsigned int)LoadMap::terrainFlatList.size())
    {
        const QString &terrainName=LoadMap::terrainFlatList.at(terrainIndex);
        LoadMap::Terrain * terrain=LoadMap::terrainNameToObject.value(terrainName);
        if(terrain->outsideBorder)
        {
            Tiled::TileLayer * const transitionLayerMask=LoadMap::searchTileLayerByName(tiledMap,"[T]"+terrainName);
            layerToDelete.push_back(transitionLayerMask);

            //search the layer
            int tileLayerIndex=0;
            while(true)
            {
                if(tiledMap.layerCount()<tileLayerIndex)
                {
                    std::cerr << "tiledMap.layerCount()<tileLayerIndexTemp (abort)" << std::endl;
                    abort();
                }
                Tiled::Layer * tempLayer=tiledMap.layerAt(tileLayerIndex);
                if(tempLayer->isTileLayer() &&
                        //tempLayer==transitionLayerMask
                        tempLayer->name()==terrain->tmp_layerString
                        )
                    break;
                else
                    tileLayerIndex++;
            }

            unsigned int y=0;
            while(y<h)
            {
                unsigned int x=0;
                while(x<w)
                {
                    const Tiled::Cell &cell=transitionLayerMask->cellAt(x,y);
                    if(cell.tile!=NULL)
                    {
                        int tileLayerIndexTemp=tileLayerIndex;
                        while(true)
                        {
                            if(tiledMap.layerCount()<tileLayerIndexTemp)
                            {
                                std::cerr << "tiledMap.layerCount()<tileLayerIndexTemp (abort)" << std::endl;
                                abort();
                            }
                            Tiled::Layer * tempLayer=tiledMap.layerAt(tileLayerIndexTemp);
                            if(!tempLayer->isTileLayer())
                            {
                                std::cerr << "!tempLayer->isTileLayer() (abort)" << std::endl;
                                abort();
                            }
                            if(static_cast<Tiled::TileLayer *>(tempLayer)->cellAt(x,y).tile!=NULL)
                            {
                                if(cell.tile!=terrain->tile)
                                    tileLayerIndexTemp++;
                                else
                                {
                                    tileLayerIndexTemp++;
                                    //clean the upper layer
                                    while(tileLayerIndexTemp<(tileLayerIndex+3))
                                    {
                                        Tiled::TileLayer * tileLayer=static_cast<Tiled::TileLayer *>(tiledMap.layerAt(tileLayerIndexTemp));
                                        Tiled::Cell cell;
                                        cell.tile=NULL;
                                        cell.flippedHorizontally=false;
                                        cell.flippedVertically=false;
                                        cell.flippedAntiDiagonally=false;
                                        tileLayer->setCell(x,y,cell);
                                        tileLayerIndexTemp++;
                                    }
                                    tileLayerIndexTemp=tileLayerIndex;
                                    break;
                                }
                            }
                            else
                                break;
                        }
                        Tiled::TileLayer * tileLayer=static_cast<Tiled::TileLayer *>(tiledMap.layerAt(tileLayerIndexTemp));
                        tileLayer->setCell(x,y,cell);
                    }
                    x++;
                }
                y++;
            }
        }
        terrainIndex++;
    }
    unsigned int index=0;
    while(index<layerToDelete.size())
    {
        Tiled::TileLayer * layer=layerToDelete.at(index);
        //layer->setVisible(false);
        const int indexOfLayer=tiledMap.indexOfLayer(layer->name());
        if(indexOfLayer>=0)
            delete tiledMap.takeLayerAt(indexOfLayer);
        index++;
    }
}