From f8f976763b4d272b4801f8b99eb542caa12fc3fe Mon Sep 17 00:00:00 2001 From: Xavier ASUS Date: Sun, 25 Nov 2018 21:07:28 +0100 Subject: Removed city background. Fixed some serious issues regarding building and tile data. --- Source/MapEditor/MapEditor.pro.user | 2 +- Source/MapEditor/buildings.ini | 4 + Source/MapEditor/mainwindow.cpp | 483 ++++++++++++++++++++++++++++-------- Source/MapEditor/mainwindow.h | 32 ++- Source/MapEditor/settings.ini | 2 +- 5 files changed, 418 insertions(+), 105 deletions(-) create mode 100644 Source/MapEditor/buildings.ini (limited to 'Source/MapEditor') diff --git a/Source/MapEditor/MapEditor.pro.user b/Source/MapEditor/MapEditor.pro.user index 2ef5a22..a31f63f 100644 --- a/Source/MapEditor/MapEditor.pro.user +++ b/Source/MapEditor/MapEditor.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/Source/MapEditor/buildings.ini b/Source/MapEditor/buildings.ini new file mode 100644 index 0000000..5eb7823 --- /dev/null +++ b/Source/MapEditor/buildings.ini @@ -0,0 +1,4 @@ +[buildings] +path = "../../Sprites/BLDNGS1.bmp" +building0 = "Nothing" +building1 = "Hangar" diff --git a/Source/MapEditor/mainwindow.cpp b/Source/MapEditor/mainwindow.cpp index e641a4d..923fca4 100644 --- a/Source/MapEditor/mainwindow.cpp +++ b/Source/MapEditor/mainwindow.cpp @@ -50,17 +50,37 @@ MainWindow::~MainWindow() void MainWindow::loadBuildingData(void) { - const QString filePath = "./buildings.ini"; + const QString path = "./buildings.ini"; - QFile f(filePath); + QSettings settings(path, QSettings::IniFormat); - if (f.open(QFile::ReadOnly)) + if (QFile(path).exists()) { + settings.beginGroup("buildings"); + buildingPath = settings.value("path").toString(); + + int i = 0; + + while (1) + { + QString buildingNumber = "building" + QString::number(i); + QString buildingName = settings.value(buildingNumber, "").toString(); + + if (buildingName.isEmpty() ) + { + break; + } + + buildingData.insert(i++, buildingName); + ui.buildingList->addItem(buildingName); + } + + settings.endGroup(); } else { - showError(tr("Could not open file ") + filePath); + showError(path + tr(" could not be found")); } } @@ -102,8 +122,8 @@ void MainWindow::onListItemSelected(void) { if (selected_item != -1) { - const int map_buffer_pos = static_cast((DATA_HEADER_SIZE + 1) - + (static_cast(selected_item) * sizeof(quint16))); + const int map_buffer_pos = static_cast(DATA_HEADER_SIZE + + (static_cast(selected_item + 1) * sizeof(quint16))); //map_buffer_pos++; // MSB: building data, LSB: terrain data. if (map_buffer_pos < map_buffer.count()) @@ -255,14 +275,11 @@ void MainWindow::processMapFile(const QByteArray& data) && not tilesetPaths[1].isEmpty()) { - QPixmap tile1(tilesetPaths[0]); - QPixmap tile2(tilesetPaths[1]); - const int expected_filesize = (DATA_HEADER_SIZE + (level_size * level_size)); if (data.count() >= expected_filesize) { - parseMapData(ds, tile1, tile2); + parseMapData(ds); } else { @@ -277,7 +294,7 @@ void MainWindow::processMapFile(const QByteArray& data) } } -void MainWindow::parseMapData(QDataStream& ds, const QPixmap& tileSet, const QPixmap& tileSet2) +void MainWindow::parseMapData(QDataStream& ds) { char airportName[0x1A]; @@ -285,91 +302,229 @@ void MainWindow::parseMapData(QDataStream& ds, const QPixmap& tileSet, const QPi ui.airportName_Label->setText(QString(airportName)); - ds.skipRawData(0x3B - 0x1A); + ds.skipRawData(0x3C - 0x1A); gscene.clear(); gscene.clearFocus(); + QList buildingData; + + for (int j = 0; j < level_size; j++) { for (int i = 0; i < level_size; i++) { - enum - { - TILE_GRASS = 0, - TILE_ASPHALT_WITH_BORDERS, - TILE_WATER, - TILE_ASPHALT, - - TILE_RWY_MID, - TILE_RWY_START_1, - TILE_RWY_START_2, - TILE_PARKING, - - TILE_PARKING_2, - TILE_TAXIWAY_INTERSECT_GRASS, - TILE_TAXIWAY_GRASS, - TILE_TAXIWAY_CORNER_GRASS, - - TILE_HALF_WATER_1, - TILE_HALF_WATER_2, - TILE_RWY_HOLDING_POINT, - TILE_RWY_HOLDING_POINT_2, - - TILE_RWY_EXIT, - TILE_TAXIWAY_CORNER_GRASS_2, - TILE_TAXIWAY_4WAY_CROSSING, - TILE_RWY_EXIT_2, - - LAST_TILE_TILESET1 = TILE_RWY_EXIT_2, - - TILE_UNUSED_1, - TILE_TAXIWAY_CORNER_GRASS_3, - - FIRST_TILE_TILESET2 = TILE_UNUSED_1, - LAST_TILE_TILESET2 = TILE_TAXIWAY_CORNER_GRASS_3 - }; - - int u; - int v; char byte[2]; ds.readRawData(byte, 2); - quint8 CurrentTile = static_cast(byte[1]); - quint8 CurrentBuilding = static_cast(byte[0]); - quint8 buildingNoMirror = CurrentBuilding & 0x7F; - quint8 tileNoMirror = CurrentTile & 0x7F; - const QPixmap* p = nullptr; - if (tileNoMirror <= LAST_TILE_TILESET1) - { - p = &tileSet; - } - else if (tileNoMirror <= LAST_TILE_TILESET2) - { - p = &tileSet2; - CurrentTile -= FIRST_TILE_TILESET2; - tileNoMirror -= FIRST_TILE_TILESET2; - } + qDebug() << "i = " + QString::number(i); + qDebug() << "j = " + QString::number(j); + qDebug() << QString::number(byte[0]); + qDebug() << QString::number(byte[1]); + qDebug() << ""; + + buildingData.append(static_cast(byte[0])); + addTile(static_cast(byte[1]), i, j); + } + } + + for (int j = 0; j < level_size; j++) + { + for (int i = 0; i < level_size; i++) + { + addBuilding(buildingData.at(i + (j* level_size)), i, j); + } + } - if (p != nullptr) + ui.graphicsView->setScene(&gscene); + ui.graphicsView->show(); + ui.graphicsView->centerOn(QPointF(320, 480)); +} + +#define NODATA \ +{ \ + false, \ + { \ + 0, \ + 0, \ + 0 \ + }, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0 \ +} + +#define BUILDING_DATA(building) \ +{ \ + true, \ + { \ + building##_OFFSET_X, \ + building##_OFFSET_Y, \ + 0 \ + }, \ + building##_ORIGIN_X, \ + building##_ORIGIN_Y, \ + building##_W, \ + building##_H, \ + building##_U, \ + building##_V \ +} + +void MainWindow::addBuilding(quint8 CurrentBuilding, const int i, const int j) +{ + if (CurrentBuilding) + { + enum + { + BUILDING_NONE, + BUILDING_HANGAR, + BUILDING_ILS, + BUILDING_ATC_TOWER, + BUILDING_ATC_LOC, + BUILDING_TERMINAL, + BUILDING_TERMINAL_2, + BUILDING_GATE, + + LAST_BUILDING = BUILDING_GATE, + MAX_BUILDING_ID + }; + + enum + { + BUILDING_ATC_LOC_OFFSET_X = TILE_SIZE >> 1, + BUILDING_ATC_LOC_OFFSET_Y = TILE_SIZE >> 1, + + BUILDING_ILS_OFFSET_X = 0, + BUILDING_ILS_OFFSET_Y = 0, + + BUILDING_GATE_OFFSET_X = (TILE_SIZE >> 1) - 4, + BUILDING_GATE_OFFSET_Y = 0, + + BUILDING_HANGAR_OFFSET_X = 4, + BUILDING_HANGAR_OFFSET_Y = TILE_SIZE >> 1, + + BUILDING_TERMINAL_OFFSET_X = 0, + BUILDING_TERMINAL_OFFSET_Y = TILE_SIZE >> 1, + + BUILDING_TERMINAL_2_OFFSET_X = BUILDING_TERMINAL_OFFSET_X, + BUILDING_TERMINAL_2_OFFSET_Y = BUILDING_TERMINAL_OFFSET_Y, + + BUILDING_ATC_TOWER_OFFSET_X = TILE_SIZE >> 2, + BUILDING_ATC_TOWER_OFFSET_Y = TILE_SIZE >> 1, + }; + + enum + { + BUILDING_ILS_U = 34, + BUILDING_ILS_V = 0, + BUILDING_ILS_W = 24, + BUILDING_ILS_H = 34, + + BUILDING_GATE_U = 0, + BUILDING_GATE_V = 70, + BUILDING_GATE_W = 28, + BUILDING_GATE_H = 25, + + BUILDING_HANGAR_U = 0, + BUILDING_HANGAR_V = 0, + BUILDING_HANGAR_W = 34, + BUILDING_HANGAR_H = 28, + + BUILDING_TERMINAL_U = 0, + BUILDING_TERMINAL_V = 34, + BUILDING_TERMINAL_W = 51, + BUILDING_TERMINAL_H = 36, + + BUILDING_TERMINAL_2_U = 51, + BUILDING_TERMINAL_2_V = BUILDING_TERMINAL_V, + BUILDING_TERMINAL_2_W = BUILDING_TERMINAL_W, + BUILDING_TERMINAL_2_H = BUILDING_TERMINAL_H, + + BUILDING_ATC_TOWER_U = 58, + BUILDING_ATC_TOWER_V = 0, + BUILDING_ATC_TOWER_W = 29, + BUILDING_ATC_TOWER_H = 34, + }; + + enum + { + BUILDING_ILS_ORIGIN_X = 10, + BUILDING_ILS_ORIGIN_Y = 22, + + BUILDING_GATE_ORIGIN_X = 20, + BUILDING_GATE_ORIGIN_Y = 8, + + BUILDING_TERMINAL_ORIGIN_X = 20, + BUILDING_TERMINAL_ORIGIN_Y = 11, + + BUILDING_TERMINAL_2_ORIGIN_X = BUILDING_TERMINAL_ORIGIN_X, + BUILDING_TERMINAL_2_ORIGIN_Y = BUILDING_TERMINAL_ORIGIN_Y, + + BUILDING_HANGAR_ORIGIN_X = 16, + BUILDING_HANGAR_ORIGIN_Y = 12, + + BUILDING_ATC_TOWER_ORIGIN_X = 12, + BUILDING_ATC_TOWER_ORIGIN_Y = 20, + }; + + static const struct + { + bool init; + IsometricPos IsoPos; // Offset inside tile + short orig_x; // Coordinate X origin inside building sprite + short orig_y; // Coordinate Y origin inside building sprite + short w; // Building width + short h; // Building height + short u; // Building X offset inside texture page + short v; // Building Y offset inside texture page + } GameBuildingData[MAX_BUILDING_ID] = + { + NODATA, + BUILDING_DATA(BUILDING_HANGAR), + BUILDING_DATA(BUILDING_ILS), + BUILDING_DATA(BUILDING_ATC_TOWER), + NODATA, + BUILDING_DATA(BUILDING_TERMINAL), + BUILDING_DATA(BUILDING_TERMINAL_2), + BUILDING_DATA(BUILDING_GATE), + }; + + enum + { + TILE_SIZE_BIT_SHIFT = 6 + }; + + const quint8 CurrentBuildingNoMirror = CurrentBuilding & 0x7F; + + if (CurrentBuildingNoMirror < MAX_BUILDING_ID) + { + if (GameBuildingData[CurrentBuildingNoMirror].init) { - if (CurrentTile & TILE_MIRROR_FLAG) - { - u = static_cast((tileNoMirror % 4) * 64); - v = static_cast((tileNoMirror / 4) * 48); - } - else - { - u = static_cast((CurrentTile % 4) * 64); - v = static_cast((CurrentTile / 4) * 48); - } + // Determine rendering order depending on Y value. + const short x_bldg_offset = GameBuildingData[CurrentBuildingNoMirror].IsoPos.x; + const short y_bldg_offset = GameBuildingData[CurrentBuildingNoMirror].IsoPos.y; + const short z_bldg_offset = GameBuildingData[CurrentBuildingNoMirror].IsoPos.z; - QImage cropped = p->copy(u, v, 64, 48).toImage(); + IsometricPos buildingIsoPos; - if (CurrentTile & TILE_MIRROR_FLAG) - { - cropped = cropped.mirrored(true, false); - } + buildingIsoPos.x = static_cast(i << TILE_SIZE_BIT_SHIFT) + x_bldg_offset; + buildingIsoPos.y = static_cast(j << TILE_SIZE_BIT_SHIFT) - y_bldg_offset; + buildingIsoPos.z = z_bldg_offset; + + // Isometric -> Cartesian conversion + CartesianPos buildingCartPos = isometricToCartesian(buildingIsoPos); + + QPixmap p = QPixmap(buildingPath); + + QImage cropped = p.copy(GameBuildingData[CurrentBuildingNoMirror].u, + GameBuildingData[CurrentBuildingNoMirror].v, + GameBuildingData[CurrentBuildingNoMirror].w, + GameBuildingData[CurrentBuildingNoMirror].h).toImage(); + + cropped = cropped.convertToFormat(QImage::Format_ARGB32); // or maybe other format bool selected = false; @@ -410,35 +565,161 @@ void MainWindow::parseMapData(QDataStream& ds, const QPixmap& tileSet, const QPi if (it != nullptr) { - const int x = ((i * TILE_SIZE) - (i * (TILE_SIZE / 2))) - (j * (TILE_SIZE / 2)); - const int y = (j * (TILE_SIZE / 4)) + (i * (TILE_SIZE / 4)); + // Define new coordinates for building. + const int x = buildingCartPos.x - GameBuildingData[CurrentBuilding].orig_x; + const int y = buildingCartPos.y - GameBuildingData[CurrentBuilding].orig_y; it->setX(x); it->setY(y); + } + } + } + } +} +#undef NODATA +#undef BUILDING_DATA - if (ui.showNumbers_Checkbox->isChecked() ) - { - QGraphicsTextItem* const io = new QGraphicsTextItem(); +void MainWindow::addTile(quint8 CurrentTile, const int i, const int j) +{ + enum + { + TILE_GRASS, + TILE_ASPHALT_WITH_BORDERS, + TILE_WATER, + TILE_ASPHALT, - if (io != nullptr) - { - io->setPos(x + (TILE_SIZE / 4), y); - io->setPlainText(QString::number(i + (j * level_size))); + TILE_RWY_MID, + TILE_RWY_START_1, + TILE_RWY_START_2, + TILE_PARKING, - gscene.addItem(io); + TILE_PARKING_2, + TILE_TAXIWAY_INTERSECT_GRASS, + TILE_TAXIWAY_GRASS, + TILE_TAXIWAY_CORNER_GRASS, - /* Append pointer to the list so it can be - * safely removed on the constructor. */ - textItems.append(io); - } - } + TILE_HALF_WATER_1, + TILE_HALF_WATER_2, + TILE_RWY_HOLDING_POINT, + TILE_RWY_HOLDING_POINT_2, + + TILE_RWY_EXIT, + TILE_TAXIWAY_CORNER_GRASS_2, + TILE_TAXIWAY_4WAY_CROSSING, + TILE_RWY_EXIT_2, + + LAST_TILE_TILESET1 = TILE_RWY_EXIT_2, + + TILE_UNUSED_1, + TILE_TAXIWAY_CORNER_GRASS_3, + + FIRST_TILE_TILESET2 = TILE_UNUSED_1, + LAST_TILE_TILESET2 = TILE_TAXIWAY_CORNER_GRASS_3 + }; + + const QPixmap tileset(tilesetPaths[0]); + const QPixmap tileset2(tilesetPaths[1]); + + quint8 tileNoMirror = CurrentTile & 0x7F; + const QPixmap* p = nullptr; + + if (tileNoMirror <= LAST_TILE_TILESET1) + { + p = &tileset; + } + else if (tileNoMirror <= LAST_TILE_TILESET2) + { + p = &tileset2; + CurrentTile -= FIRST_TILE_TILESET2; + tileNoMirror -= FIRST_TILE_TILESET2; + } + + if (p != nullptr) + { + int u; + int v; + + if (CurrentTile & TILE_MIRROR_FLAG) + { + u = static_cast((tileNoMirror % 4) * 64); + v = static_cast((tileNoMirror / 4) * 48); + } + else + { + u = static_cast((CurrentTile % 4) * 64); + v = static_cast((CurrentTile / 4) * 48); + } + + QImage cropped = p->copy(u, v, 64, 48).toImage(); + + if (CurrentTile & TILE_MIRROR_FLAG) + { + cropped = cropped.mirrored(true, false); + } + + bool selected = false; + + if (selected_item != -1) + { + if (selected_item == ((j * level_size) + i)) + { + selected = true; + } + } + + cropped = cropped.convertToFormat(QImage::Format_ARGB32); // or maybe other format + + for (int i = 0; i < cropped.width(); i++) + { + for (int j = 0; j < cropped.height(); j++) + { + QColor rgb = cropped.pixel(i, j); + + if (rgb == QColor(Qt::magenta)) + { + cropped.setPixel(i, j, qRgba(0,0,0,0)); + } + else if (selected ) + { + QColor c = cropped.pixelColor(i, j); + + c.setRed(255 - c.red()); + c.setBlue(255 - c.blue()); + c.setGreen(255 - c.green()); + + cropped.setPixel(i, j, qRgb(c.red(), c.green(), c.blue())); } } } - } - ui.graphicsView->setScene(&gscene); - ui.graphicsView->show(); + QGraphicsPixmapItem* const it = gscene.addPixmap(QPixmap::fromImage(cropped)); + + if (it != nullptr) + { + const int x = ((i * TILE_SIZE) - (i * (TILE_SIZE / 2))) - (j * (TILE_SIZE / 2)); + const int y = (j * (TILE_SIZE / 4)) + (i * (TILE_SIZE / 4)); + + it->setX(x); + it->setY(y); + + if (ui.showNumbers_Checkbox->isChecked() ) + { + QGraphicsTextItem* const io = new QGraphicsTextItem(); + + if (io != nullptr) + { + io->setPos(x + (TILE_SIZE / 4), y); + io->setPlainText(QString::number(i + (j * level_size))); + + gscene.addItem(io); + + /* Append pointer to the list so it can be + * safely removed on the constructor. */ + textItems.append(io); + } + } + } + } } bool MainWindow::checkFile(QFile& f, QFile::OpenModeFlag flags) @@ -486,9 +767,7 @@ void MainWindow::loadTilesetData(void) { const QString filePath = "./tileset.ini"; - QFile f(filePath); - - if (f.exists()) + if (QFile(filePath).exists()) { QSettings tilesetFile("./tileset.ini", QSettings::IniFormat); QStringList tilesets_to_check; diff --git a/Source/MapEditor/mainwindow.h b/Source/MapEditor/mainwindow.h index 97e39ef..6b27128 100644 --- a/Source/MapEditor/mainwindow.h +++ b/Source/MapEditor/mainwindow.h @@ -33,11 +33,39 @@ public: void closeEvent(QCloseEvent*); private: + struct IsometricPos + { + short x; + short y; + short z; + }; + + struct CartesianPos + { + short x; + short y; + }; + bool checkFile(QFile &f, QFile::OpenModeFlag flags = QFile::ReadOnly); void appSettings(void); void loadTilesetData(void); void loadBuildingData(void); - void parseMapData(QDataStream &ds, const QPixmap &tileSet, const QPixmap &tileSet2); + void parseMapData(QDataStream &ds); + void addTile(quint8 CurrentTile, const int i, const int j); + void addBuilding(quint8 CurrentBuilding, const int i, const int j); + CartesianPos isometricToCartesian(const IsometricPos& ptrIsoPos) const + { + CartesianPos retCartPos; + + retCartPos.x = ptrIsoPos.x - (ptrIsoPos.x >> 1); + retCartPos.x -= ptrIsoPos.y >> 1; + + retCartPos.y = ptrIsoPos.y >> 2; + retCartPos.y += ptrIsoPos.x >> 2; + retCartPos.y -= ptrIsoPos.z; + + return retCartPos; + } Ui::MainWindow ui; QString _last_dir; @@ -46,10 +74,12 @@ private: QByteArray map_buffer; int selected_item; QHash tilesetData; + QHash buildingData; QList textItems; QShortcut tileSet; QShortcut tileMoveUp; QString tilesetPaths[2]; + QString buildingPath; private slots: void loadMap(void); diff --git a/Source/MapEditor/settings.ini b/Source/MapEditor/settings.ini index 4300b90..5ad5294 100644 --- a/Source/MapEditor/settings.ini +++ b/Source/MapEditor/settings.ini @@ -1,3 +1,3 @@ [app_settings] last_dir=/home/xavier/Airport/Levels/LEVEL3.LVL -window_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x5U\0\0\x2\xdb\0\0\0\xaa\0\0\0P\0\0\x4\x41\0\0\x2\xd7\0\0\0\0\x2\0\0\0\x5V\0\0\0\0\0\0\0\x1d\0\0\x5U\0\0\x2\xdb) +window_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x5U\0\0\x2\xdb\0\0\0\xa5\0\0\0\x1d\0\0\x4<\0\0\x2\xa4\0\0\0\0\x2\0\0\0\x5V\0\0\0\0\0\0\0\x1d\0\0\x5U\0\0\x2\xdb) -- cgit v1.2.3