diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui
index d7c4abe1..50e03e88 100644
--- a/forms/mainwindow.ui
+++ b/forms/mainwindow.ui
@@ -2931,7 +2931,7 @@
-
+
@@ -3222,9 +3222,9 @@
Open Config Folder
-
+
- Import Map from Advance Map 1.92...
+ Import Layout from Advance Map 1.92...
diff --git a/include/core/advancemapparser.h b/include/core/advancemapparser.h
new file mode 100644
index 00000000..c3cb76cb
--- /dev/null
+++ b/include/core/advancemapparser.h
@@ -0,0 +1,18 @@
+#ifndef ADVANCEMAPPARSER_H
+#define ADVANCEMAPPARSER_H
+
+#include
+#include
+#include
+
+class Project;
+class Layout;
+class Metatile;
+
+namespace AdvanceMapParser {
+ Layout *parseLayout(const QString &filepath, bool *error, const Project *project);
+ QList parseMetatiles(const QString &filepath, bool *error, bool primaryTileset);
+ QList parsePalette(const QString &filepath, bool *error);
+};
+
+#endif // ADVANCEMAPPARSER_H
diff --git a/include/core/mapparser.h b/include/core/mapparser.h
deleted file mode 100644
index 4032154a..00000000
--- a/include/core/mapparser.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef MAPPARSER_H
-#define MAPPARSER_H
-
-#include "maplayout.h"
-#include "project.h"
-#include
-#include
-
-class MapParser
-{
-public:
- MapParser();
- Layout *parse(QString filepath, bool *error, Project *project);
-};
-
-#endif // MAPPARSER_H
diff --git a/include/core/metatileparser.h b/include/core/metatileparser.h
deleted file mode 100644
index b85e5b36..00000000
--- a/include/core/metatileparser.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-#ifndef METATILEPARSER_H
-#define METATILEPARSER_H
-
-#include "metatile.h"
-#include
-
-namespace MetatileParser {
- QList parse(QString filepath, bool *error, bool primaryTileset);
-}
-
-#endif // METATILEPARSER_H
diff --git a/include/core/parseutil.h b/include/core/parseutil.h
index e3df8375..d184646b 100644
--- a/include/core/parseutil.h
+++ b/include/core/parseutil.h
@@ -5,6 +5,7 @@
#include "heallocation.h"
#include "log.h"
#include "orderedjson.h"
+#include "orderedmap.h"
#include
#include
@@ -57,7 +58,7 @@ public:
QMap readCDefinesByRegex(const QString &filename, const QStringList ®exList);
QMap readCDefinesByName(const QString &filename, const QStringList &names);
QStringList readCDefineNames(const QString &filename, const QStringList ®exList);
- QMap> readCStructs(const QString &, const QString & = "", const QHash = { });
+ tsl::ordered_map> readCStructs(const QString &, const QString & = "", const QHash& = {});
QList getLabelMacros(const QList&, const QString&);
QStringList getLabelValues(const QList&, const QString&);
bool tryParseJsonFile(QJsonDocument *out, const QString &filepath);
diff --git a/include/lib/fex/parser.h b/include/lib/fex/parser.h
index 6a6b9e43..c79b34a2 100644
--- a/include/lib/fex/parser.h
+++ b/include/lib/fex/parser.h
@@ -9,6 +9,7 @@
#include "array_value.h"
#include "define_statement.h"
#include "lexer.h"
+#include "orderedmap.h"
namespace fex
{
@@ -19,9 +20,9 @@ namespace fex
std::vector Parse(std::vector tokens);
std::vector ParseTopLevelArrays(std::vector tokens);
- std::map ParseTopLevelObjects(std::vector tokens);
+ tsl::ordered_map ParseTopLevelObjects(std::vector tokens);
- std::map ReadDefines(const std::string &filename, std::vector matching);
+ tsl::ordered_map ReadDefines(const std::string &filename, std::vector matching);
private:
int EvaluateExpression(std::vector tokens);
diff --git a/include/mainwindow.h b/include/mainwindow.h
index a8dbca1f..53889dff 100644
--- a/include/mainwindow.h
+++ b/include/mainwindow.h
@@ -194,7 +194,6 @@ private slots:
void onNewMapGroupCreated(const QString &groupName);
void onNewLayoutCreated(Layout *layout);
void onMapLoaded(Map *map);
- void importMapFromAdvanceMap1_92();
void onMapRulerStatusChanged(const QString &);
void applyUserShortcuts();
void markMapEdited();
@@ -238,7 +237,7 @@ private slots:
void on_action_Export_Map_Image_triggered();
void on_actionExport_Stitched_Map_Image_triggered();
void on_actionExport_Map_Timelapse_Image_triggered();
- void on_actionImport_Map_from_Advance_Map_1_92_triggered();
+ void on_actionImport_Layout_from_Advance_Map_1_92_triggered();
void on_pushButton_AddConnection_clicked();
void on_button_OpenDiveMap_clicked();
diff --git a/include/project.h b/include/project.h
index 19b757db..c1a36a80 100644
--- a/include/project.h
+++ b/include/project.h
@@ -189,7 +189,7 @@ public:
void saveTilesetMetatiles(Tileset*);
void saveTilesetTilesImage(Tileset*);
void saveTilesetPalettes(Tileset*);
- void appendTilesetLabel(QString label, QString isSecondaryStr);
+ void appendTilesetLabel(const QString &label, const QString &isSecondaryStr);
bool readTilesetLabels();
bool readTilesetMetatileLabels();
bool readRegionMapSections();
diff --git a/include/ui/newlayoutdialog.h b/include/ui/newlayoutdialog.h
index 49047cc7..c90a408b 100644
--- a/include/ui/newlayoutdialog.h
+++ b/include/ui/newlayoutdialog.h
@@ -20,7 +20,7 @@ class NewLayoutDialog : public QDialog
public:
explicit NewLayoutDialog(QWidget *parent = nullptr, Project *project = nullptr);
~NewLayoutDialog();
- void init(Layout *);
+ void copyFrom(const Layout &);
void accept() override;
signals:
@@ -39,7 +39,6 @@ private:
void saveSettings();
bool isExistingLayout() const;
- void useLayoutSettings(Layout *mapLayout);
private slots:
//void on_comboBox_Layout_currentTextChanged(const QString &text);//TODO
diff --git a/porymap.pro b/porymap.pro
index 1cc9497c..1dfaf4b1 100644
--- a/porymap.pro
+++ b/porymap.pro
@@ -21,7 +21,8 @@ QMAKE_TARGET_BUNDLE_PREFIX = com.pret
VERSION = 5.4.1
DEFINES += PORYMAP_VERSION=\\\"$$VERSION\\\"
-SOURCES += src/core/block.cpp \
+SOURCES += src/core/advancemapparser.cpp \
+ src/core/block.cpp \
src/core/bitpacker.cpp \
src/core/blockdata.cpp \
src/core/events.cpp \
@@ -32,9 +33,7 @@ SOURCES += src/core/block.cpp \
src/core/mapconnection.cpp \
src/core/mapheader.cpp \
src/core/maplayout.cpp \
- src/core/mapparser.cpp \
src/core/metatile.cpp \
- src/core/metatileparser.cpp \
src/core/network.cpp \
src/core/paletteutil.cpp \
src/core/parseutil.cpp \
@@ -127,7 +126,8 @@ SOURCES += src/core/block.cpp \
src/ui/updatepromoter.cpp \
src/ui/wildmonchart.cpp
-HEADERS += include/core/block.h \
+HEADERS += include/core/advancemapparser.h \
+ include/core/block.h \
include/core/bitpacker.h \
include/core/blockdata.h \
include/core/events.h \
@@ -139,9 +139,7 @@ HEADERS += include/core/block.h \
include/core/mapconnection.h \
include/core/mapheader.h \
include/core/maplayout.h \
- include/core/mapparser.h \
include/core/metatile.h \
- include/core/metatileparser.h \
include/core/network.h \
include/core/paletteutil.h \
include/core/parseutil.h \
diff --git a/src/core/advancemapparser.cpp b/src/core/advancemapparser.cpp
new file mode 100644
index 00000000..6af7476e
--- /dev/null
+++ b/src/core/advancemapparser.cpp
@@ -0,0 +1,217 @@
+#include "advancemapparser.h"
+#include "log.h"
+#include "project.h"
+#include "maplayout.h"
+
+Layout *AdvanceMapParser::parseLayout(const QString &filepath, bool *error, const Project *project)
+{
+ QFile file(filepath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ *error = true;
+ logError(QString("Could not open Advance Map 1.92 Map .map file '%1': ").arg(filepath) + file.errorString());
+ return nullptr;
+ }
+
+ QByteArray in = file.readAll();
+ file.close();
+
+ if (in.length() < 20 || in.length() % 2 != 0) {
+ *error = true;
+ logError(QString("Advance Map 1.92 Map .map file '%1' is an unexpected size.").arg(filepath));
+ return nullptr;
+ }
+
+ int borderWidth = static_cast(in.at(16)); // 0 in RSE .map files
+ int borderHeight = static_cast(in.at(17)); // 0 in RSE .map files
+ int numBorderTiles = borderWidth * borderHeight; // 0 if RSE
+
+ int mapDataOffset = 20 + (numBorderTiles * 2); // FRLG .map files store border metatile data after the header
+ int mapWidth = static_cast(in.at(0)) |
+ (static_cast(in.at(1)) << 8) |
+ (static_cast(in.at(2)) << 16) |
+ (static_cast(in.at(3)) << 24);
+ int mapHeight = static_cast(in.at(4)) |
+ (static_cast(in.at(5)) << 8) |
+ (static_cast(in.at(6)) << 16) |
+ (static_cast(in.at(7)) << 24);
+ int mapPrimaryTilesetNum = static_cast(in.at(8)) |
+ (static_cast(in.at(9)) << 8) |
+ (static_cast(in.at(10)) << 16) |
+ (static_cast(in.at(11)) << 24);
+ int mapSecondaryTilesetNum = static_cast(in.at(12)) |
+ (static_cast(in.at(13)) << 8) |
+ (static_cast(in.at(14)) << 16) |
+ (static_cast(in.at(15)) << 24);
+
+ int numMetatiles = mapWidth * mapHeight;
+ int expectedFileSize = 20 + (numBorderTiles * 2) + (numMetatiles * 2);
+ if (in.length() != expectedFileSize) {
+ *error = true;
+ logError(QString(".map file is an unexpected size. Expected %1 bytes, but it has %2 bytes.").arg(expectedFileSize).arg(in.length()));
+ return nullptr;
+ }
+
+ Blockdata blockdata;
+ for (int i = mapDataOffset; (i + 1) < in.length(); i += 2) {
+ uint16_t word = static_cast((in[i] & 0xff) + ((in[i + 1] & 0xff) << 8));
+ blockdata.append(word);
+ }
+
+ Blockdata border;
+ if (numBorderTiles != 0) {
+ for (int i = 20; (i + 1) < mapDataOffset; i += 2) {
+ uint16_t word = static_cast((in[i] & 0xff) + ((in[i + 1] & 0xff) << 8));
+ border.append(word);
+ }
+ }
+
+ Layout *mapLayout = new Layout();
+ mapLayout->width = mapWidth;
+ mapLayout->height = mapHeight;
+ mapLayout->border_width = (borderWidth == 0) ? DEFAULT_BORDER_WIDTH : borderWidth;
+ mapLayout->border_height = (borderHeight == 0) ? DEFAULT_BORDER_HEIGHT : borderHeight;
+
+ const QList tilesets = project->tilesetLabelsOrdered;
+
+ if (mapPrimaryTilesetNum > tilesets.size())
+ mapLayout->tileset_primary_label = project->getDefaultPrimaryTilesetLabel();
+ else
+ mapLayout->tileset_primary_label = tilesets.at(mapPrimaryTilesetNum);
+
+ if (mapSecondaryTilesetNum > tilesets.size())
+ mapLayout->tileset_secondary_label = project->getDefaultSecondaryTilesetLabel();
+ else
+ mapLayout->tileset_secondary_label = tilesets.at(mapSecondaryTilesetNum);
+
+ mapLayout->blockdata = blockdata;
+
+ if (!border.isEmpty()) {
+ mapLayout->border = border;
+ }
+
+ return mapLayout;
+}
+
+QList AdvanceMapParser::parseMetatiles(const QString &filepath, bool *error, bool primaryTileset)
+{
+ QFile file(filepath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ *error = true;
+ logError(QString("Could not open Advance Map 1.92 Metatile .bvd file '%1': ").arg(filepath) + file.errorString());
+ return { };
+ }
+
+ QByteArray in = file.readAll();
+ file.close();
+
+ if (in.length() < 9 || in.length() % 2 != 0) {
+ *error = true;
+ logError(QString("Advance Map 1.92 Metatile .bvd file '%1' is an unexpected size.").arg(filepath));
+ return { };
+ }
+
+ int projIdOffset = in.length() - 4;
+ int metatileSize = 16;
+ BaseGameVersion version;
+ if (in.at(projIdOffset + 0) == 'R'
+ && in.at(projIdOffset + 1) == 'S'
+ && in.at(projIdOffset + 2) == 'E'
+ && in.at(projIdOffset + 3) == ' ') {
+ // ruby and emerald are handled equally here.
+ version = BaseGameVersion::pokeemerald;
+ } else if (in.at(projIdOffset + 0) == 'F'
+ && in.at(projIdOffset + 1) == 'R'
+ && in.at(projIdOffset + 2) == 'L'
+ && in.at(projIdOffset + 3) == 'G') {
+ version = BaseGameVersion::pokefirered;
+ } else {
+ *error = true;
+ logError(QString("Detected unsupported game type from .bvd file. Last 4 bytes of file must be 'RSE ' or 'FRLG'."));
+ return { };
+ }
+
+ int attrSize = Metatile::getDefaultAttributesSize(version);
+ int maxMetatiles = primaryTileset ? Project::getNumMetatilesPrimary() : Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary();
+ int numMetatiles = static_cast(in.at(0)) |
+ (static_cast(in.at(1)) << 8) |
+ (static_cast(in.at(2)) << 16) |
+ (static_cast(in.at(3)) << 24);
+ if (numMetatiles > maxMetatiles) {
+ *error = true;
+ logError(QString(".bvd file contains data for %1 metatiles, but the maximum number of metatiles is %2.").arg(numMetatiles).arg(maxMetatiles));
+ return { };
+ }
+ if (numMetatiles < 1) {
+ *error = true;
+ logError(QString(".bvd file contains no data for metatiles."));
+ return { };
+ }
+
+ int expectedFileSize = 4 + (metatileSize * numMetatiles) + (attrSize * numMetatiles) + 4;
+ if (in.length() != expectedFileSize) {
+ *error = true;
+ logError(QString(".bvd file is an unexpected size. Expected %1 bytes, but it has %2 bytes.").arg(expectedFileSize).arg(in.length()));
+ return { };
+ }
+
+ QList metatiles;
+ for (int i = 0; i < numMetatiles; i++) {
+ Metatile *metatile = new Metatile();
+ QList tiles;
+ for (int j = 0; j < 8; j++) {
+ int metatileOffset = 4 + i * metatileSize + j * 2;
+ Tile tile(static_cast(
+ static_cast(in.at(metatileOffset)) |
+ (static_cast(in.at(metatileOffset + 1)) << 8)));
+ tiles.append(tile);
+ }
+
+ // AdvanceMap .bvd files only contain 8 tiles of data per metatile.
+ // If the user has triple-layer metatiles enabled we need to fill the remaining 4 tiles ourselves.
+ if (projectConfig.tripleLayerMetatilesEnabled) {
+ Tile tile = Tile();
+ for (int j = 0; j < 4; j++)
+ tiles.append(tile);
+ }
+
+ int attrOffset = 4 + (numMetatiles * metatileSize) + (i * attrSize);
+ uint32_t attributes = 0;
+ for (int j = 0; j < attrSize; j++)
+ attributes |= static_cast(in.at(attrOffset + j)) << (8 * j);
+ metatile->setAttributes(attributes, version);
+ metatile->tiles = tiles;
+ metatiles.append(metatile);
+ }
+
+ return metatiles;
+}
+
+QList AdvanceMapParser::parsePalette(const QString &filepath, bool *error) {
+ QFile file(filepath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ *error = true;
+ logError(QString("Could not open Advance Map 1.92 palette file '%1': ").arg(filepath) + file.errorString());
+ return QList();
+ }
+
+ QByteArray in = file.readAll();
+ file.close();
+
+ if (in.length() % 4 != 0) {
+ *error = true;
+ logError(QString("Advance Map 1.92 palette file '%1' had an unexpected format. File's length must be a multiple of 4, but the length is %2.").arg(filepath).arg(in.length()));
+ return QList();
+ }
+
+ QList palette;
+ int i = 0;
+ while (i < in.length()) {
+ unsigned char red = qMin(qMax(static_cast(in.at(i + 0)), 0u), 255u);
+ unsigned char green = qMin(qMax(static_cast(in.at(i + 1)), 0u), 255u);
+ unsigned char blue = qMin(qMax(static_cast(in.at(i + 2)), 0u), 255u);
+ palette.append(qRgb(red, green, blue));
+ i += 4;
+ }
+
+ return palette;
+}
diff --git a/src/core/mapparser.cpp b/src/core/mapparser.cpp
deleted file mode 100644
index 3d4258bd..00000000
--- a/src/core/mapparser.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include "mapparser.h"
-#include "config.h"
-#include "log.h"
-#include "project.h"
-
-MapParser::MapParser()
-{
-}
-
-Layout *MapParser::parse(QString filepath, bool *error, Project *project)
-{
- QFile file(filepath);
- if (!file.open(QIODevice::ReadOnly)) {
- *error = true;
- logError(QString("Could not open Advance Map 1.92 Map .map file '%1': ").arg(filepath) + file.errorString());
- return nullptr;
- }
-
- QByteArray in = file.readAll();
- file.close();
-
- if (in.length() < 20 || in.length() % 2 != 0) {
- *error = true;
- logError(QString("Advance Map 1.92 Map .map file '%1' is an unexpected size.").arg(filepath));
- return nullptr;
- }
-
- int borderWidth = static_cast(in.at(16)); // 0 in RSE .map files
- int borderHeight = static_cast(in.at(17)); // 0 in RSE .map files
- int numBorderTiles = borderWidth * borderHeight; // 0 if RSE
-
- int mapDataOffset = 20 + (numBorderTiles * 2); // FRLG .map files store border metatile data after the header
- int mapWidth = static_cast(in.at(0)) |
- (static_cast(in.at(1)) << 8) |
- (static_cast(in.at(2)) << 16) |
- (static_cast(in.at(3)) << 24);
- int mapHeight = static_cast(in.at(4)) |
- (static_cast(in.at(5)) << 8) |
- (static_cast(in.at(6)) << 16) |
- (static_cast(in.at(7)) << 24);
- int mapPrimaryTilesetNum = static_cast(in.at(8)) |
- (static_cast(in.at(9)) << 8) |
- (static_cast(in.at(10)) << 16) |
- (static_cast(in.at(11)) << 24);
- int mapSecondaryTilesetNum = static_cast(in.at(12)) |
- (static_cast(in.at(13)) << 8) |
- (static_cast(in.at(14)) << 16) |
- (static_cast(in.at(15)) << 24);
-
- int numMetatiles = mapWidth * mapHeight;
- int expectedFileSize = 20 + (numBorderTiles * 2) + (numMetatiles * 2);
- if (in.length() != expectedFileSize) {
- *error = true;
- logError(QString(".map file is an unexpected size. Expected %1 bytes, but it has %2 bytes.").arg(expectedFileSize).arg(in.length()));
- return nullptr;
- }
-
- Blockdata blockdata;
- for (int i = mapDataOffset; (i + 1) < in.length(); i += 2) {
- uint16_t word = static_cast((in[i] & 0xff) + ((in[i + 1] & 0xff) << 8));
- blockdata.append(word);
- }
-
- Blockdata border;
- if (numBorderTiles != 0) {
- for (int i = 20; (i + 1) < mapDataOffset; i += 2) {
- uint16_t word = static_cast((in[i] & 0xff) + ((in[i + 1] & 0xff) << 8));
- border.append(word);
- }
- }
-
- Layout *mapLayout = new Layout();
- mapLayout->width = mapWidth;
- mapLayout->height = mapHeight;
- mapLayout->border_width = (borderWidth == 0) ? DEFAULT_BORDER_WIDTH : borderWidth;
- mapLayout->border_height = (borderHeight == 0) ? DEFAULT_BORDER_HEIGHT : borderHeight;
-
- QList tilesets = project->tilesetLabelsOrdered;
-
- if (mapPrimaryTilesetNum > tilesets.size())
- mapLayout->tileset_primary_label = tilesets.at(0);
- else
- mapLayout->tileset_primary_label = tilesets.at(mapPrimaryTilesetNum);
-
- if (mapSecondaryTilesetNum > tilesets.size())
- mapLayout->tileset_secondary_label = tilesets.at(1);
- else
- mapLayout->tileset_secondary_label = tilesets.at(mapSecondaryTilesetNum);
-
- mapLayout->blockdata = blockdata;
-
- if (!border.isEmpty()) {
- mapLayout->border = border;
- }
-
- return mapLayout;
-}
diff --git a/src/core/metatileparser.cpp b/src/core/metatileparser.cpp
deleted file mode 100644
index 104b757a..00000000
--- a/src/core/metatileparser.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#include "metatileparser.h"
-#include "config.h"
-#include "log.h"
-#include "project.h"
-#include
-
-QList MetatileParser::parse(QString filepath, bool *error, bool primaryTileset)
-{
- QFile file(filepath);
- if (!file.open(QIODevice::ReadOnly)) {
- *error = true;
- logError(QString("Could not open Advance Map 1.92 Metatile .bvd file '%1': ").arg(filepath) + file.errorString());
- return { };
- }
-
- QByteArray in = file.readAll();
- file.close();
-
- if (in.length() < 9 || in.length() % 2 != 0) {
- *error = true;
- logError(QString("Advance Map 1.92 Metatile .bvd file '%1' is an unexpected size.").arg(filepath));
- return { };
- }
-
- int projIdOffset = in.length() - 4;
- int metatileSize = 16;
- BaseGameVersion version;
- if (in.at(projIdOffset + 0) == 'R'
- && in.at(projIdOffset + 1) == 'S'
- && in.at(projIdOffset + 2) == 'E'
- && in.at(projIdOffset + 3) == ' ') {
- // ruby and emerald are handled equally here.
- version = BaseGameVersion::pokeemerald;
- } else if (in.at(projIdOffset + 0) == 'F'
- && in.at(projIdOffset + 1) == 'R'
- && in.at(projIdOffset + 2) == 'L'
- && in.at(projIdOffset + 3) == 'G') {
- version = BaseGameVersion::pokefirered;
- } else {
- *error = true;
- logError(QString("Detected unsupported game type from .bvd file. Last 4 bytes of file must be 'RSE ' or 'FRLG'."));
- return { };
- }
-
- int attrSize = Metatile::getDefaultAttributesSize(version);
- int maxMetatiles = primaryTileset ? Project::getNumMetatilesPrimary() : Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary();
- int numMetatiles = static_cast(in.at(0)) |
- (static_cast(in.at(1)) << 8) |
- (static_cast(in.at(2)) << 16) |
- (static_cast(in.at(3)) << 24);
- if (numMetatiles > maxMetatiles) {
- *error = true;
- logError(QString(".bvd file contains data for %1 metatiles, but the maximum number of metatiles is %2.").arg(numMetatiles).arg(maxMetatiles));
- return { };
- }
- if (numMetatiles < 1) {
- *error = true;
- logError(QString(".bvd file contains no data for metatiles."));
- return { };
- }
-
- int expectedFileSize = 4 + (metatileSize * numMetatiles) + (attrSize * numMetatiles) + 4;
- if (in.length() != expectedFileSize) {
- *error = true;
- logError(QString(".bvd file is an unexpected size. Expected %1 bytes, but it has %2 bytes.").arg(expectedFileSize).arg(in.length()));
- return { };
- }
-
- QList metatiles;
- for (int i = 0; i < numMetatiles; i++) {
- Metatile *metatile = new Metatile();
- QList tiles;
- for (int j = 0; j < 8; j++) {
- int metatileOffset = 4 + i * metatileSize + j * 2;
- Tile tile(static_cast(
- static_cast(in.at(metatileOffset)) |
- (static_cast(in.at(metatileOffset + 1)) << 8)));
- tiles.append(tile);
- }
-
- // AdvanceMap .bvd files only contain 8 tiles of data per metatile.
- // If the user has triple-layer metatiles enabled we need to fill the remaining 4 tiles ourselves.
- if (projectConfig.tripleLayerMetatilesEnabled) {
- Tile tile = Tile();
- for (int j = 0; j < 4; j++)
- tiles.append(tile);
- }
-
- int attrOffset = 4 + (numMetatiles * metatileSize) + (i * attrSize);
- uint32_t attributes = 0;
- for (int j = 0; j < attrSize; j++)
- attributes |= static_cast(in.at(attrOffset + j)) << (8 * j);
- metatile->setAttributes(attributes, version);
- metatile->tiles = tiles;
- metatiles.append(metatile);
- }
-
- return metatiles;
-}
diff --git a/src/core/paletteutil.cpp b/src/core/paletteutil.cpp
index da281ce6..929336b2 100644
--- a/src/core/paletteutil.cpp
+++ b/src/core/paletteutil.cpp
@@ -1,4 +1,5 @@
#include "paletteutil.h"
+#include "advancemapparser.h"
#include "log.h"
#include
#include
@@ -6,7 +7,6 @@
QList parsePal(QString filepath, bool *error);
QList parseJASC(QString filepath, bool *error);
-QList parseAdvanceMapPal(QString filepath, bool *error);
QList parseAdobeColorTable(QString filepath, bool *error);
QList parseTileLayerPro(QString filepath, bool *error);
QList parseAdvancePaletteEditor(QString filepath, bool *error);
@@ -81,7 +81,7 @@ QList parsePal(QString filepath, bool *error) {
return parseJASC(filepath, error);
} else {
file.close();
- return parseAdvanceMapPal(filepath, error);
+ return AdvanceMapParser::parsePalette(filepath, error);
}
}
@@ -152,38 +152,6 @@ QList parseJASC(QString filepath, bool *error) {
return palette;
}
-QList parseAdvanceMapPal(QString filepath, bool *error) {
- QFile file(filepath);
- if (!file.open(QIODevice::ReadOnly)) {
- *error = true;
- logError(QString("Could not open Advance Map 1.92 palette file '%1': ").arg(filepath) + file.errorString());
- return QList();
- }
-
- QByteArray in = file.readAll();
- file.close();
-
- if (in.length() % 4 != 0) {
- *error = true;
- logError(QString("Advance Map 1.92 palette file '%1' had an unexpected format. File's length must be a multiple of 4, but the length is %2.").arg(filepath).arg(in.length()));
- return QList();
- }
-
- QList palette;
- int i = 0;
- while (i < in.length()) {
- unsigned char red = static_cast(in.at(i));
- unsigned char green = static_cast(in.at(i + 1));
- unsigned char blue = static_cast(in.at(i + 2));
- palette.append(qRgb(clampColorValue(red),
- clampColorValue(green),
- clampColorValue(blue)));
- i += 4;
- }
-
- return palette;
-}
-
QList parseAdobeColorTable(QString filepath, bool *error) {
QFile file(filepath);
if (!file.open(QIODevice::ReadOnly)) {
diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp
index 9664fdc7..1aff9cd5 100644
--- a/src/core/parseutil.cpp
+++ b/src/core/parseutil.cpp
@@ -593,13 +593,13 @@ bool ParseUtil::gameStringToBool(QString gameString, bool * ok) {
return gameStringToInt(gameString, ok) != 0;
}
-QMap> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash memberMap) {
+tsl::ordered_map> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash &memberMap) {
QString filePath = this->root + "/" + filename;
auto cParser = fex::Parser();
auto tokens = fex::Lexer().LexFile(filePath.toStdString());
- auto structs = cParser.ParseTopLevelObjects(tokens);
- QMap> structMaps;
- for (auto it = structs.begin(); it != structs.end(); it++) {
+ auto topLevelObjects = cParser.ParseTopLevelObjects(tokens);
+ tsl::ordered_map> structs;
+ for (auto it = topLevelObjects.begin(); it != topLevelObjects.end(); it++) {
QString structLabel = QString::fromStdString(it->first);
if (structLabel.isEmpty()) continue;
if (!label.isEmpty() && label != structLabel) continue; // Speed up parsing if only looking for a particular symbol
@@ -617,9 +617,9 @@ QMap> ParseUtil::readCStructs(const QString &fi
}
i++;
}
- structMaps.insert(structLabel, values);
+ structs[structLabel] = values;
}
- return structMaps;
+ return structs;
}
QList ParseUtil::getLabelMacros(const QList &list, const QString &label) {
diff --git a/src/lib/fex/parser.cpp b/src/lib/fex/parser.cpp
index bb5c90a8..1c010528 100644
--- a/src/lib/fex/parser.cpp
+++ b/src/lib/fex/parser.cpp
@@ -337,9 +337,9 @@ namespace fex
return DefineStatement(identifer, value);
}
- std::map Parser::ReadDefines(const std::string &filename, std::vector matching)
+ tsl::ordered_map Parser::ReadDefines(const std::string &filename, std::vector matching)
{
- std::map out;
+ tsl::ordered_map out;
Lexer lexer;
auto tokens = lexer.LexFile(filename);
@@ -488,12 +488,12 @@ namespace fex
return items;
}
- std::map Parser::ParseTopLevelObjects(std::vector tokens)
+ tsl::ordered_map Parser::ParseTopLevelObjects(std::vector tokens)
{
index_ = 0;
tokens_ = std::move(tokens);
- std::map items;
+ tsl::ordered_map items;
while (index_ < tokens_.size())
{
diff --git a/src/lib/fex/parser_util.cpp b/src/lib/fex/parser_util.cpp
index 0f375b81..3a5d47f9 100644
--- a/src/lib/fex/parser_util.cpp
+++ b/src/lib/fex/parser_util.cpp
@@ -17,7 +17,7 @@ QStringList ParserUtil::ReadDefines(QString filename, QString prefix)
fex::Parser parser;
std::vector match_list = { prefix.toStdString() + ".*" };
- std::map defines = parser.ReadDefines(filepath.toStdString(), match_list);
+ tsl::ordered_map defines = parser.ReadDefines(filepath.toStdString(), match_list);
QStringList out;
for(auto const& define : defines) {
@@ -39,7 +39,7 @@ QStringList ParserUtil::ReadDefinesValueSort(QString filename, QString prefix)
fex::Parser parser;
std::vector match_list = { prefix.toStdString() + ".*" };
- std::map defines = parser.ReadDefines(filepath.toStdString(), match_list);
+ tsl::ordered_map defines = parser.ReadDefines(filepath.toStdString(), match_list);
QMultiMap defines_keyed_by_value;
for (const auto& pair : defines) {
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 8c483f1f..7af3d100 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -14,7 +14,7 @@
#include "editcommands.h"
#include "flowlayout.h"
#include "shortcut.h"
-#include "mapparser.h"
+#include "advancemapparser.h"
#include "prefab.h"
#include "montabwidget.h"
#include "imageexport.h"
@@ -1634,7 +1634,7 @@ void MainWindow::on_actionNew_Tileset_triggered() {
int index = insertTilesetLabel(&editor->project->secondaryTilesetLabels, createTilesetDialog->fullSymbolName);
this->ui->comboBox_SecondaryTileset->insertItem(index, createTilesetDialog->fullSymbolName);
}
- insertTilesetLabel(&editor->project->tilesetLabelsOrdered, createTilesetDialog->fullSymbolName);
+ editor->project->tilesetLabelsOrdered.append(createTilesetDialog->fullSymbolName);
QMessageBox msgBox(this);
msgBox.setText("Successfully created tileset.");
@@ -2712,20 +2712,14 @@ void MainWindow::on_actionExport_Map_Timelapse_Image_triggered() {
showExportMapImageWindow(ImageExporterMode::Timelapse);
}
-void MainWindow::on_actionImport_Map_from_Advance_Map_1_92_triggered(){
- importMapFromAdvanceMap1_92();
-}
-
-void MainWindow::importMapFromAdvanceMap1_92()
-{
- QString filepath = FileDialog::getOpenFileName(this, "Import Map from Advance Map 1.92", "", "Advance Map 1.92 Map Files (*.map)");
+void MainWindow::on_actionImport_Layout_from_Advance_Map_1_92_triggered() {
+ QString filepath = FileDialog::getOpenFileName(this, "Import Layout from Advance Map 1.92", "", "Advance Map 1.92 Map Files (*.map)");
if (filepath.isEmpty()) {
return;
}
- MapParser parser;
bool error = false;
- Layout *mapLayout = parser.parse(filepath, &error, editor->project);
+ Layout *mapLayout = AdvanceMapParser::parseLayout(filepath, &error, editor->project);
if (error) {
QMessageBox msgBox(this);
msgBox.setText("Failed to import map from Advance Map 1.92 .map file.");
@@ -2734,11 +2728,13 @@ void MainWindow::importMapFromAdvanceMap1_92()
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Icon::Critical);
msgBox.exec();
+ delete mapLayout;
return;
}
- openNewMapDialog();
- this->newMapDialog->init(mapLayout);
+ openNewLayoutDialog();
+ this->newLayoutDialog->copyFrom(*mapLayout);
+ delete mapLayout;
}
void MainWindow::showExportMapImageWindow(ImageExporterMode mode) {
diff --git a/src/project.cpp b/src/project.cpp
index 825c3c48..2f37e24a 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -1115,6 +1115,9 @@ bool Project::loadLayoutTilesets(Layout *layout) {
return true;
}
+// TODO: We are parsing the tileset headers file whenever we load a tileset for the first time.
+// At a minimum this means we're parsing the file three times per session (twice here for the first map's tilesets, once on launch in Project::readTilesetLabels).
+// We can cache the header data instead and only parse it once on launch.
Tileset* Project::loadTileset(QString label, Tileset *tileset) {
auto memberMap = Tileset::getHeaderMemberMap(this->usingAsmTilesets);
if (this->usingAsmTilesets) {
@@ -1134,14 +1137,14 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) {
tileset->metatile_attrs_label = values.value(memberMap.key("metatileAttributes"));
} else {
// Read C tileset header
- const auto structs = parser.readCStructs(projectConfig.getFilePath(ProjectFilePath::tilesets_headers), label, memberMap);
+ auto structs = parser.readCStructs(projectConfig.getFilePath(ProjectFilePath::tilesets_headers), label, memberMap);
if (!structs.contains(label)) {
return nullptr;
}
if (tileset == nullptr) {
tileset = new Tileset;
}
- const auto tilesetAttributes = structs[label];
+ auto tilesetAttributes = structs[label];
tileset->name = label;
tileset->is_secondary = ParseUtil::gameStringToBool(tilesetAttributes.value("isSecondary"));
tileset->tiles_label = tilesetAttributes.value("tiles");
@@ -1579,7 +1582,7 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
}
QString Project::findMetatileLabelsTileset(QString label) {
- for (QString tilesetName : this->tilesetLabelsOrdered) {
+ for (const QString &tilesetName : this->tilesetLabelsOrdered) {
QString metatileLabelPrefix = Tileset::getMetatileLabelPrefix(tilesetName);
if (label.startsWith(metatileLabelPrefix))
return tilesetName;
@@ -2046,7 +2049,7 @@ QString Project::getDefaultSecondaryTilesetLabel() const {
return defaultLabel;
}
-void Project::appendTilesetLabel(QString label, QString isSecondaryStr) {
+void Project::appendTilesetLabel(const QString &label, const QString &isSecondaryStr) {
bool ok;
bool isSecondary = ParseUtil::gameStringToBool(isSecondaryStr, &ok);
if (!ok) {
@@ -2080,20 +2083,18 @@ bool Project::readTilesetLabels() {
QRegularExpressionMatch match = iter.next();
appendTilesetLabel(match.captured("label"), match.captured("isSecondary"));
}
- this->primaryTilesetLabels.sort();
- this->secondaryTilesetLabels.sort();
- this->tilesetLabelsOrdered.sort();
filename = asm_filename; // For error reporting further down
} else {
this->usingAsmTilesets = false;
const auto structs = parser.readCStructs(filename, "", Tileset::getHeaderMemberMap(this->usingAsmTilesets));
- const QStringList labels = structs.keys();
- // TODO: This is alphabetical, AdvanceMap import wants the vanilla order in tilesetLabelsOrdered
- for (const auto &tilesetLabel : labels){
- appendTilesetLabel(tilesetLabel, structs[tilesetLabel].value("isSecondary"));
+ for (auto i = structs.cbegin(); i != structs.cend(); i++){
+ appendTilesetLabel(i.key(), i.value().value("isSecondary"));
}
}
+ this->primaryTilesetLabels.sort();
+ this->secondaryTilesetLabels.sort();
+
bool success = true;
if (this->secondaryTilesetLabels.isEmpty()) {
logError(QString("Failed to find any secondary tilesets in %1").arg(filename));
@@ -2784,7 +2785,7 @@ bool Project::readEventGraphics() {
};
QString filepath = projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx_info);
- const auto gfxInfos = parser.readCStructs(filepath, "", gfxInfoMemberMap);
+ auto gfxInfos = parser.readCStructs(filepath, "", gfxInfoMemberMap);
QMap picTables = parser.readCArrayMulti(projectConfig.getFilePath(ProjectFilePath::data_obj_event_pic_tables));
QMap graphicIncbins = parser.readCIncbinMulti(projectConfig.getFilePath(ProjectFilePath::data_obj_event_gfx));
@@ -2794,7 +2795,7 @@ bool Project::readEventGraphics() {
if (!gfxInfos.contains(info_label))
continue;
- const auto gfxInfoAttributes = gfxInfos[info_label];
+ auto gfxInfoAttributes = gfxInfos[info_label];
auto eventGraphics = new EventGraphics;
eventGraphics->inanimate = ParseUtil::gameStringToBool(gfxInfoAttributes.value("inanimate"));
diff --git a/src/ui/newlayoutdialog.cpp b/src/ui/newlayoutdialog.cpp
index 0f67545e..73822ba8 100644
--- a/src/ui/newlayoutdialog.cpp
+++ b/src/ui/newlayoutdialog.cpp
@@ -41,18 +41,27 @@ NewLayoutDialog::~NewLayoutDialog()
delete ui;
}
-// Creating new map from AdvanceMap import
+// Creating new layout from AdvanceMap import
// TODO: Re-use for a "Duplicate Layout" option?
-void NewLayoutDialog::init(Layout *layoutToCopy) {
+void NewLayoutDialog::copyFrom(const Layout &layoutToCopy) {
if (this->importedLayout)
delete this->importedLayout;
this->importedLayout = new Layout();
- this->importedLayout->blockdata = layoutToCopy->blockdata;
- if (!layoutToCopy->border.isEmpty())
- this->importedLayout->border = layoutToCopy->border;
+ this->importedLayout->blockdata = layoutToCopy.blockdata;
+ if (!layoutToCopy.border.isEmpty())
+ this->importedLayout->border = layoutToCopy.border;
- useLayoutSettings(this->importedLayout);
+ this->settings->width = layoutToCopy.width;
+ this->settings->height = layoutToCopy.height;
+ this->settings->borderWidth = layoutToCopy.border_width;
+ this->settings->borderHeight = layoutToCopy.border_height;
+ this->settings->primaryTilesetLabel = layoutToCopy.tileset_primary_label;
+ this->settings->secondaryTilesetLabel = layoutToCopy.tileset_secondary_label;
+
+ // Don't allow changes to the layout settings
+ ui->newLayoutForm->setSettings(*this->settings);
+ ui->newLayoutForm->setDisabled(true);
}
void NewLayoutDialog::saveSettings() {
@@ -61,20 +70,6 @@ void NewLayoutDialog::saveSettings() {
this->settings->name = ui->lineEdit_Name->text();
}
-void NewLayoutDialog::useLayoutSettings(Layout *layout) {
- if (!layout) return;
- this->settings->width = layout->width;
- this->settings->height = layout->height;
- this->settings->borderWidth = layout->border_width;
- this->settings->borderHeight = layout->border_height;
- this->settings->primaryTilesetLabel = layout->tileset_primary_label;
- this->settings->secondaryTilesetLabel = layout->tileset_secondary_label;
- ui->newLayoutForm->setSettings(*this->settings);
-
- // Don't allow changes to the layout settings
- ui->newLayoutForm->setDisabled(true);
-}
-
bool NewLayoutDialog::validateLayoutID(bool allowEmpty) {
QString id = ui->lineEdit_LayoutID->text();
diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp
index e709bed1..b6bf1735 100644
--- a/src/ui/tileseteditor.cpp
+++ b/src/ui/tileseteditor.cpp
@@ -2,7 +2,7 @@
#include "ui_tileseteditor.h"
#include "log.h"
#include "imageproviders.h"
-#include "metatileparser.h"
+#include "advancemapparser.h"
#include "paletteutil.h"
#include "imageexport.h"
#include "config.h"
@@ -978,7 +978,7 @@ void TilesetEditor::importTilesetMetatiles(Tileset *tileset, bool primary)
}
bool error = false;
- QList metatiles = MetatileParser::parse(filepath, &error, primary);
+ QList metatiles = AdvanceMapParser::parseMetatiles(filepath, &error, primary);
if (error) {
QMessageBox msgBox(this);
msgBox.setText("Failed to import metatiles from Advance Map 1.92 .bvd file.");