region maps: save layouts, save tilemaps
This commit is contained in:
parent
1334369906
commit
43ebeb1662
4 changed files with 168 additions and 54 deletions
|
@ -84,6 +84,7 @@ public:
|
||||||
void save();
|
void save();
|
||||||
void saveTilemap();
|
void saveTilemap();
|
||||||
void saveLayout();
|
void saveLayout();
|
||||||
|
void saveConfig();// ? or do this in the editor only?
|
||||||
void saveOptions(int id, QString sec, QString name, int x, int y);
|
void saveOptions(int id, QString sec, QString name, int x, int y);
|
||||||
|
|
||||||
void resize(int width, int height);
|
void resize(int width, int height);
|
||||||
|
@ -98,6 +99,7 @@ public:
|
||||||
shared_ptr<TilemapTile> getTile(int x, int y);
|
shared_ptr<TilemapTile> getTile(int x, int y);
|
||||||
bool squareHasMap(int index);
|
bool squareHasMap(int index);
|
||||||
QString squareMapSection(int index);
|
QString squareMapSection(int index);
|
||||||
|
void setSquareMapSection(int index, QString section);
|
||||||
int squareX(int index);
|
int squareX(int index);
|
||||||
int squareY(int index);
|
int squareY(int index);
|
||||||
bool squareInLayout(int x, int y);
|
bool squareInLayout(int x, int y);
|
||||||
|
@ -116,6 +118,9 @@ public:
|
||||||
QVector<uint8_t> getTiles();
|
QVector<uint8_t> getTiles();
|
||||||
void setTiles(QVector<uint8_t> tileIds);
|
void setTiles(QVector<uint8_t> tileIds);
|
||||||
|
|
||||||
|
QByteArray getTilemap();
|
||||||
|
void setTilemap(QByteArray newTilemap);
|
||||||
|
|
||||||
QStringList getLayers() { return this->layout_layers; }
|
QStringList getLayers() { return this->layout_layers; }
|
||||||
void setLayer(QString layer) { this->current_layer = layer; }
|
void setLayer(QString layer) { this->current_layer = layer; }
|
||||||
QString getLayer() { return this->current_layer; }
|
QString getLayer() { return this->current_layer; }
|
||||||
|
@ -142,7 +147,7 @@ public:
|
||||||
QString fullPath(QString local);
|
QString fullPath(QString local);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// TODO: defaults needed?
|
||||||
tsl::ordered_map<QString, MapSectionEntry> *region_map_entries = nullptr;
|
tsl::ordered_map<QString, MapSectionEntry> *region_map_entries = nullptr;
|
||||||
|
|
||||||
QString alias;
|
QString alias;
|
||||||
|
@ -150,18 +155,14 @@ private:
|
||||||
int tilemap_width;
|
int tilemap_width;
|
||||||
int tilemap_height;
|
int tilemap_height;
|
||||||
|
|
||||||
// default is 32x20 (or 30x20 / screen size??)
|
|
||||||
int region_width;
|
int region_width;
|
||||||
int region_height;
|
int region_height;
|
||||||
|
|
||||||
// default is 28x15
|
|
||||||
int layout_width;
|
int layout_width;
|
||||||
int layout_height;
|
int layout_height;
|
||||||
|
|
||||||
int offset_left;
|
int offset_left;
|
||||||
int offset_top;
|
int offset_top;
|
||||||
//int ;
|
|
||||||
//int img_height_;
|
|
||||||
|
|
||||||
TilemapFormat tilemap_format;
|
TilemapFormat tilemap_format;
|
||||||
|
|
||||||
|
@ -175,30 +176,22 @@ private:
|
||||||
QString entries_path;
|
QString entries_path;
|
||||||
QString layout_path;
|
QString layout_path;
|
||||||
|
|
||||||
// TODO: default values?
|
|
||||||
QString layout_array_label;
|
QString layout_array_label;
|
||||||
bool layout_uses_layers = false;
|
bool layout_uses_layers = false;
|
||||||
//QList<QString> layout_layers;
|
QStringList layout_constants;
|
||||||
|
QString layout_qualifiers;
|
||||||
|
|
||||||
//QList<RegionMapSquare> map_squares;
|
|
||||||
QList<shared_ptr<TilemapTile>> tilemap;
|
QList<shared_ptr<TilemapTile>> tilemap;
|
||||||
|
|
||||||
// what about separate array for layout
|
QStringList layout_layers; // TODO: is this used?
|
||||||
// and a pointer to an entries / map sections object (from project? or editor?)
|
|
||||||
QStringList layout_layers;
|
|
||||||
QString current_layer;
|
QString current_layer;
|
||||||
|
|
||||||
// TODO: qstring, or {section name, x, y, section_id, has_map}
|
// TODO: just use ordered map?
|
||||||
QMap<QString, QList<LayoutSquare>> layouts; // key: layer, value: layout list
|
QMap<QString, QList<LayoutSquare>> layouts; // key: layer, value: layout
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
QString city_map_tiles_path;
|
QString city_map_tiles_path;
|
||||||
|
|
||||||
// todo: no???? why would i be doing this it's pointless
|
|
||||||
// let the user figure this shit out
|
|
||||||
bool region_map_png_needs_saving = false;
|
|
||||||
bool city_map_png_needs_saving = false;
|
|
||||||
|
|
||||||
int get_tilemap_index(int x, int y);
|
int get_tilemap_index(int x, int y);
|
||||||
int get_layout_index(int x, int y);
|
int get_layout_index(int x, int y);
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
virtual void setVFlip(bool vFlip) { this->vFlip_ = vFlip; }
|
virtual void setVFlip(bool vFlip) { this->vFlip_ = vFlip; }
|
||||||
virtual void setPalette(int palette) { this->palette_ = palette; }
|
virtual void setPalette(int palette) { this->palette_ = palette; }
|
||||||
|
|
||||||
virtual QString info() {
|
virtual QString info() const {
|
||||||
return QString("Tile: 0x") + QString("%1 ").arg(this->id(), 4, 16, QChar('0')).toUpper();
|
return QString("Tile: 0x") + QString("%1 ").arg(this->id(), 4, 16, QChar('0')).toUpper();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -70,6 +70,8 @@ public:
|
||||||
PlainTile(unsigned raw) : TilemapTile(raw, raw, false, false, 0) {}
|
PlainTile(unsigned raw) : TilemapTile(raw, raw, false, false, 0) {}
|
||||||
|
|
||||||
~PlainTile() {}
|
~PlainTile() {}
|
||||||
|
|
||||||
|
virtual unsigned raw () const override { return id(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class BPP4Tile : public TilemapTile {
|
class BPP4Tile : public TilemapTile {
|
||||||
|
@ -84,7 +86,11 @@ public:
|
||||||
|
|
||||||
~BPP4Tile() {}
|
~BPP4Tile() {}
|
||||||
|
|
||||||
virtual QString info() override {
|
virtual unsigned raw () const override {
|
||||||
|
return (id()) | (hFlip() << 10) | (vFlip() << 11) | (palette() << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual QString info() const override {
|
||||||
return TilemapTile::info() + QString("hFlip: %1 vFlip: %2 palette: %3").arg(this->hFlip()).arg(this->vFlip()).arg(this->palette());
|
return TilemapTile::info() + QString("hFlip: %1 vFlip: %2 palette: %3").arg(this->hFlip()).arg(this->vFlip()).arg(this->palette());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -101,7 +107,11 @@ public:
|
||||||
|
|
||||||
~BPP8Tile() {}
|
~BPP8Tile() {}
|
||||||
|
|
||||||
virtual QString info() override {
|
virtual unsigned raw () const override {
|
||||||
|
return (id()) | (hFlip() << 10) | (vFlip() << 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual QString info() const override {
|
||||||
return TilemapTile::info() + QString("hFlip: %1 vFlip: %2").arg(this->hFlip()).arg(this->vFlip());
|
return TilemapTile::info() + QString("hFlip: %1 vFlip: %2").arg(this->hFlip()).arg(this->vFlip());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -84,43 +84,19 @@ bool RegionMap::loadTilemap(poryjson::Json tilemapJson) {
|
||||||
this->palette_path = tilemapObject["palette"].string_value();
|
this->palette_path = tilemapObject["palette"].string_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile tilemapFile(fullPath(tilemap_path));
|
QFile tilemapFile(fullPath(this->tilemap_path));
|
||||||
if (!tilemapFile.open(QIODevice::ReadOnly)) {
|
if (!tilemapFile.open(QIODevice::ReadOnly)) {
|
||||||
logError(QString("Failed to open region map tilemap file %1.").arg(tilemap_path));
|
logError(QString("Failed to open region map tilemap file %1.").arg(tilemap_path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QDataStream dataStream(&tilemapFile);
|
|
||||||
dataStream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
|
|
||||||
if (tilemapFile.size() < tilemapBytes()) {
|
if (tilemapFile.size() < tilemapBytes()) {
|
||||||
logError(QString("The region map tilemap at %1 is too small.").arg(tilemap_path));
|
logError(QString("The region map tilemap at %1 is too small.").arg(tilemap_path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->tilemap.resize(tilemapSize());
|
QByteArray newTilemap = tilemapFile.readAll();
|
||||||
switch (this->tilemap_format) {
|
this->setTilemap(newTilemap);
|
||||||
case TilemapFormat::Plain:
|
|
||||||
for (int i = 0; i < tilemapBytes(); i++) {
|
|
||||||
uint8_t tile;
|
|
||||||
dataStream >> tile;
|
|
||||||
this->tilemap[i] = make_shared<PlainTile>(tile);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TilemapFormat::BPP_4:
|
|
||||||
for (int i = 0; i < tilemapBytes(); i+=2) {
|
|
||||||
uint16_t tile;
|
|
||||||
dataStream >> tile;
|
|
||||||
this->tilemap[i / 2] = make_shared<BPP4Tile>(tile & 0xffff);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TilemapFormat::BPP_8:
|
|
||||||
for (int i = 0; i < tilemapBytes(); i+=2) {
|
|
||||||
uint16_t tile;
|
|
||||||
dataStream >> tile;
|
|
||||||
this->tilemap[i / 2] = make_shared<BPP8Tile>(tile & 0xffff);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tilemapFile.close();
|
tilemapFile.close();
|
||||||
|
|
||||||
|
@ -133,6 +109,9 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: reset other values here
|
||||||
|
this->layout_constants.clear();
|
||||||
|
|
||||||
poryjson::Json::object layoutObject = layoutJson.object_items();
|
poryjson::Json::object layoutObject = layoutJson.object_items();
|
||||||
|
|
||||||
QString layoutFormat = layoutObject["format"].string_value();
|
QString layoutFormat = layoutObject["format"].string_value();
|
||||||
|
@ -201,13 +180,16 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
|
||||||
QRegularExpressionMatch match = re.match(text);
|
QRegularExpressionMatch match = re.match(text);
|
||||||
if (match.hasMatch()) {
|
if (match.hasMatch()) {
|
||||||
// TODO: keep track of labels and consts
|
// TODO: keep track of labels and consts
|
||||||
QString qualifiers = match.captured("qual_1") + match.captured("qual_2");
|
QString qualifiers = match.captured("qual_1") + " " + match.captured("qual_2");
|
||||||
QString type = match.captured("type");
|
QString type = match.captured("type");
|
||||||
QString label = match.captured("label");
|
QString label = match.captured("label");
|
||||||
QStringList constants;
|
QStringList constants;
|
||||||
if (!match.captured("const_1").isNull()) constants.append(match.captured("const_1"));
|
if (!match.captured("const_1").isNull()) constants.append(match.captured("const_1"));
|
||||||
if (!match.captured("const_2").isNull()) constants.append(match.captured("const_2"));
|
if (!match.captured("const_2").isNull()) constants.append(match.captured("const_2"));
|
||||||
if (!match.captured("const_3").isNull()) constants.append(match.captured("const_3"));
|
if (!match.captured("const_3").isNull()) constants.append(match.captured("const_3"));
|
||||||
|
this->layout_constants = constants;
|
||||||
|
this->layout_qualifiers = qualifiers + " " + type;
|
||||||
|
this->layout_array_label = label;
|
||||||
|
|
||||||
// find layers
|
// find layers
|
||||||
QRegularExpression reLayers("(?<layer>\\[(?<label>LAYER_[A-Za-z0-9_]+)\\][^\\[\\]]+)");
|
QRegularExpression reLayers("(?<layer>\\[(?<label>LAYER_[A-Za-z0-9_]+)\\][^\\[\\]]+)");
|
||||||
|
@ -261,18 +243,75 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
|
||||||
|
|
||||||
void RegionMap::save() {
|
void RegionMap::save() {
|
||||||
logInfo("Saving region map data.");
|
logInfo("Saving region map data.");
|
||||||
|
|
||||||
|
saveTilemap();
|
||||||
|
saveLayout();
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionMap::saveTilemap() {
|
void RegionMap::saveTilemap() {
|
||||||
// TODO
|
QFile tilemapFile(fullPath(this->tilemap_path));
|
||||||
|
if (!tilemapFile.open(QIODevice::WriteOnly)) {
|
||||||
|
logError(QString("Failed to open region map tilemap file %1 for writing.").arg(this->tilemap_path));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tilemapFile.write(this->getTilemap());
|
||||||
|
tilemapFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionMap::saveLayout() {
|
void RegionMap::saveLayout() {
|
||||||
// TODO
|
switch (this->layout_format) {
|
||||||
|
case LayoutFormat::Binary:
|
||||||
|
{
|
||||||
|
QByteArray data;
|
||||||
|
for (int m = 0; m < this->layout_height; m++) {
|
||||||
|
for (int n = 0; n < this->layout_width; n++) {
|
||||||
|
int i = n + this->layout_width * m;
|
||||||
|
data.append(this->project->mapSectionNameToValue.value(this->layouts["main"][i].map_section));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QFile bfile(fullPath(this->layout_path));
|
||||||
|
if (!bfile.open(QIODevice::WriteOnly)) {
|
||||||
|
logError("Failed to open region map layout binary for writing.");
|
||||||
|
}
|
||||||
|
bfile.write(data);
|
||||||
|
bfile.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LayoutFormat::CArray:
|
||||||
|
{
|
||||||
|
QString text = QString("%1 %2").arg(this->layout_qualifiers).arg(this->layout_array_label);
|
||||||
|
for (QString label : this->layout_constants) {
|
||||||
|
text += QString("[%1]").arg(label);
|
||||||
|
}
|
||||||
|
text += " = {\n";
|
||||||
|
if (this->layout_layers.size() == 1) {
|
||||||
|
// TODO: single layered
|
||||||
|
// just dump the array of map sections, or save as multi dimensional [width][height]?
|
||||||
|
} else {
|
||||||
|
// multi layered
|
||||||
|
for (auto layoutName : this->layout_layers) {
|
||||||
|
text += QString(" [%1] =\n {\n").arg(layoutName);
|
||||||
|
for (int row = 0; row < this->layout_height; row++) {
|
||||||
|
text += " {";
|
||||||
|
for (int col = 0; col < this->layout_width; col++) {
|
||||||
|
int i = col + row * this->layout_width;
|
||||||
|
text += this->layouts[layoutName][i].map_section + ", ";
|
||||||
|
}
|
||||||
|
text.chop(2);
|
||||||
|
text += "},\n";
|
||||||
|
}
|
||||||
|
text += " },\n";
|
||||||
|
}
|
||||||
|
text.chop(2);
|
||||||
|
text += "\n";
|
||||||
|
}
|
||||||
|
text += "};\n";
|
||||||
|
this->project->saveTextFile(fullPath(this->layout_path), text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionMap::saveOptions(int id, QString sec, QString name, int x, int y) {
|
void RegionMap::saveOptions(int id, QString sec, QString name, int x, int y) {
|
||||||
|
@ -305,6 +344,66 @@ void RegionMap::resize(int newWidth, int newHeight) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray RegionMap::getTilemap() {
|
||||||
|
QByteArray tilemapArray;
|
||||||
|
QDataStream dataStream(&tilemapArray, QIODevice::WriteOnly);
|
||||||
|
dataStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
|
switch (this->tilemap_format) {
|
||||||
|
case TilemapFormat::Plain:
|
||||||
|
for (int i = 0; i < tilemapSize(); i++) {
|
||||||
|
uint8_t tile = this->tilemap[i]->raw();
|
||||||
|
dataStream << tile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TilemapFormat::BPP_4:
|
||||||
|
for (int i = 0; i < tilemapSize(); i++) {
|
||||||
|
uint16_t tile = this->tilemap[i]->raw();
|
||||||
|
dataStream << tile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TilemapFormat::BPP_8:
|
||||||
|
for (int i = 0; i < tilemapSize(); i++) {
|
||||||
|
uint16_t tile = this->tilemap[i]->raw();
|
||||||
|
dataStream << tile;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tilemapArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegionMap::setTilemap(QByteArray newTilemap) {
|
||||||
|
QDataStream dataStream(newTilemap);
|
||||||
|
dataStream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
|
this->tilemap.clear();
|
||||||
|
this->tilemap.resize(tilemapSize());
|
||||||
|
switch (this->tilemap_format) {
|
||||||
|
case TilemapFormat::Plain:
|
||||||
|
for (int i = 0; i < tilemapBytes(); i++) {
|
||||||
|
uint8_t tile;
|
||||||
|
dataStream >> tile;
|
||||||
|
this->tilemap[i] = make_shared<PlainTile>(tile);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TilemapFormat::BPP_4:
|
||||||
|
for (int i = 0; i < tilemapSize(); i++) {
|
||||||
|
uint16_t tile;
|
||||||
|
dataStream >> tile;
|
||||||
|
this->tilemap[i] = make_shared<BPP4Tile>(tile & 0xffff);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TilemapFormat::BPP_8:
|
||||||
|
for (int i = 0; i < tilemapSize(); i++) {
|
||||||
|
uint16_t tile;
|
||||||
|
dataStream >> tile;
|
||||||
|
this->tilemap[i] = make_shared<BPP8Tile>(tile & 0xffff);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVector<uint8_t> RegionMap::getTiles() {
|
QVector<uint8_t> RegionMap::getTiles() {
|
||||||
QVector<uint8_t> tileIds;
|
QVector<uint8_t> tileIds;
|
||||||
// TODO: change this to use TilemapTile instead of uint8_t
|
// TODO: change this to use TilemapTile instead of uint8_t
|
||||||
|
@ -396,6 +495,14 @@ QString RegionMap::squareMapSection(int index) {
|
||||||
return (layoutIndex < 0 || !this->layouts.contains(this->current_layer)) ? QString() : this->layouts[this->current_layer][layoutIndex].map_section;
|
return (layoutIndex < 0 || !this->layouts.contains(this->current_layer)) ? QString() : this->layouts[this->current_layer][layoutIndex].map_section;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RegionMap::setSquareMapSection(int index, QString section) {
|
||||||
|
int layoutIndex = tilemapToLayoutIndex(index);
|
||||||
|
if (!(layoutIndex < 0 || !this->layouts.contains(this->current_layer))) {
|
||||||
|
this->layouts[this->current_layer][layoutIndex].map_section = section;
|
||||||
|
this->layouts[this->current_layer][layoutIndex].has_map = !(section == "MAPSEC_NONE" || section.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int RegionMap::squareX(int index) {
|
int RegionMap::squareX(int index) {
|
||||||
int layoutIndex = tilemapToLayoutIndex(index);
|
int layoutIndex = tilemapToLayoutIndex(index);
|
||||||
return (layoutIndex < 0 || !this->layouts.contains(this->current_layer)) ? -1 : this->layouts[this->current_layer][layoutIndex].x;
|
return (layoutIndex < 0 || !this->layouts.contains(this->current_layer)) ? -1 : this->layouts[this->current_layer][layoutIndex].x;
|
||||||
|
|
|
@ -442,6 +442,9 @@ bool RegionMapEditor::loadCityMaps() {
|
||||||
void RegionMapEditor::on_action_RegionMap_Save_triggered() {
|
void RegionMapEditor::on_action_RegionMap_Save_triggered() {
|
||||||
// TODO: save current region map, add "Save All" to save all region maps
|
// TODO: save current region map, add "Save All" to save all region maps
|
||||||
// TODO: save the config json as well
|
// TODO: save the config json as well
|
||||||
|
this->region_map->save();
|
||||||
|
|
||||||
|
// save entries
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionMapEditor::setCurrentSquareOptions() {
|
void RegionMapEditor::setCurrentSquareOptions() {
|
||||||
|
@ -909,6 +912,7 @@ void RegionMapEditor::on_tabWidget_Region_Map_currentChanged(int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegionMapEditor::on_comboBox_RM_ConnectedMap_textActivated(const QString &mapsec) {
|
void RegionMapEditor::on_comboBox_RM_ConnectedMap_textActivated(const QString &mapsec) {
|
||||||
|
this->region_map->setSquareMapSection(this->currIndex, mapsec);
|
||||||
onRegionMapLayoutSelectedTileChanged(this->currIndex);// re-draw layout image
|
onRegionMapLayoutSelectedTileChanged(this->currIndex);// re-draw layout image
|
||||||
this->hasUnsavedChanges = true;// TODO: sometimes this is called for unknown reasons
|
this->hasUnsavedChanges = true;// TODO: sometimes this is called for unknown reasons
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue