diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 6c99e28311d3431e664dc0d0c3764c7d16fca7f6..ddda5b2b34a39c4fba15156fea97c5d84d2b8052 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -12,7 +12,8 @@ set(EDITOR_SOURCES src/main.cpp src/EditorApp.cpp src/TileBar.cpp src/TileBar.hpp src/GridItem.cpp - src/GridItem.hpp) + src/GridItem.hpp + src/HDF5Handler.cpp) set(CMAKE_AUTOMOC ON) diff --git a/editor/src/CenterGrid.cpp b/editor/src/CenterGrid.cpp index dc2ca406f703280f5bad0a65725089c20e26cfb1..ede515b25afd4f00f0d5368c46077b5875cd4497 100644 --- a/editor/src/CenterGrid.cpp +++ b/editor/src/CenterGrid.cpp @@ -15,19 +15,24 @@ CenterGrid::CenterGrid(QWidget* parent) view->setAlignment(Qt::AlignCenter | Qt::AlignCenter); // Initialize the 2D container + m_currentSpriteID = -1; const int rows = 64; const int cols = 64; gridItems.resize(rows); - for (int row = 0; row < rows; ++row) - { + m_tileIDs.resize(rows); + for (int row = 0; row < rows; row++) { gridItems[row].resize(cols); + m_tileIDs[row].resize(cols); + for (int col = 0; col < cols; col++) { + m_tileIDs[row][col] = m_currentSpriteID; + } } // Create tiles const qreal tileSize = 20.0; - for (int row = 0; row < rows; ++row) + for (int row = 0; row < rows; row++) { - for (int col = 0; col < cols; ++col) + for (int col = 0; col < cols; col++) { GridItem* tile = new GridItem(row, col, tileSize); tile->setPos(col * tileSize, row * tileSize); @@ -38,7 +43,7 @@ CenterGrid::CenterGrid(QWidget* parent) } // Set initial grid boundaries - scene->setSceneRect(0, 0, 64*tileSize, 64*tileSize); + scene->setSceneRect(0, 0, 64 * tileSize, 64 * tileSize); // Set Layout QVBoxLayout* layout = new QVBoxLayout(this); @@ -59,15 +64,17 @@ void CenterGrid::resizeEvent(QResizeEvent* event) view->fitInView(scene->sceneRect(), Qt::KeepAspectRatio); } -void CenterGrid::setCurrentSprite(const QPixmap pixmap) +void CenterGrid::setCurrentSprite(const QPixmap pixmap, const int id) { m_currentSprite = pixmap; + m_currentSpriteID = id; } void CenterGrid::onTileClicked(int row, int col) { GridItem* tile = getTile(row,col); tile->setPixmap(m_currentSprite); + m_tileIDs[row][col] = m_currentSpriteID; } GridItem* CenterGrid::getTile(int row, int col) const @@ -79,6 +86,11 @@ GridItem* CenterGrid::getTile(int row, int col) const return nullptr; } +QVector<QVector<int>> CenterGrid::getTileIDs() +{ + return m_tileIDs; +} + void CenterGrid::drawPreset(int index) { QList<QGraphicsItem*> items = scene->items(); diff --git a/editor/src/CenterGrid.hpp b/editor/src/CenterGrid.hpp index d14d51be011abb8e4df585d70fd6e03b2b7bf140..31480850073aa03129196f46227efd969131423c 100644 --- a/editor/src/CenterGrid.hpp +++ b/editor/src/CenterGrid.hpp @@ -30,7 +30,7 @@ public: * @brief Setter function to update which sprite is currently selected and needs to be places when grid clicked * @param message TEMPORARY message that is shown when tile is clicked replace with sprite data */ - void setCurrentSprite(const QPixmap pixmap); + void setCurrentSprite(const QPixmap pixmap, const int id); /** * @brief Function for drawing the currently selected sprite on a tile when tile is clicked @@ -53,6 +53,12 @@ public: */ GridItem* getTile(int row, int col) const; + /** + * @brief getter function for Vector of TileIDs + * @return QVector<QVector<int>> of TileIDs + */ + QVector<QVector<int>> getTileIDs(); + private: /** @@ -76,10 +82,20 @@ private: */ QPixmap m_currentSprite; + /** + * @brief ID of the currently selected sprite + */ + int m_currentSpriteID; + /** * @brief 2D Vector holding all GridItems, making them accessible by position on grid */ QVector<QVector<GridItem*>> gridItems; + + /** + * @brief 2D Vector holding all GridItems, making them accessible by position on grid + */ + QVector<QVector<int>> m_tileIDs; }; } // namespace editor \ No newline at end of file diff --git a/editor/src/HDF5Handler.cpp b/editor/src/HDF5Handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3f9062d7b6c12a598214f1a634b2cea70dc66b6 --- /dev/null +++ b/editor/src/HDF5Handler.cpp @@ -0,0 +1,63 @@ +#include "HDF5Handler.hpp" + +namespace editor +{ + +HDF5Handler::HDF5Handler() : m_Level("./tileset.png", 16) +{ +} + +HDF5Handler::HDF5Handler(const std::filesystem::path path) : m_Level(path) +{ +} + +void HDF5Handler::loadTilesheet(TileBar* tileBar) const +{ + const unsigned char* tiledata = m_Level.getSpritesheet().getSpritedata().data(); + const int width = m_Level.getSpritesheet().getWidth(); + const int height = m_Level.getSpritesheet().getHeight(); + + const QImage image(tiledata, width, height, QImage::Format_RGBA8888); + QPixmap pixmap = QPixmap::fromImage(image); + + // TODO: Move this to the Spritesheet class in Liblvl + const int32_t maxId = (width / 16) * (height / 16); + + QStringList tileNames; + QList<QPixmap> tiles; + + for (int32_t i = 0; i < maxId; i++) + { + auto [x, y] = m_Level.getSpritesheet().getTilePosition(i); + QRect rect(x, y, 16, 16); + tileNames << QString("tile_%1").arg(i); + tiles << pixmap.copy(rect); + } + + tileBar->populateList(tileNames, tiles); +} + +void HDF5Handler::saveRoom(int id, QString name, QVector<QVector<int>> tileIDs, QVector<QVector<int>> mobIDs) +{ + lvl::Room newRoom(id, name.toStdString(), 64, 64); + for (int row = 0; row < 64; row++) + { + for (int col = 0; col < 64; col++) + { + newRoom.placeTile({col,row}, tileIDs[row][col]); + //newRoom->placeEnemy(pos, mobIDs[row][col]); + } + } + std::vector<lvl::Room>& roomsList = m_Level.getRooms(); + roomsList.push_back(newRoom); + m_Level.saveChanges("./level.h5"); +} + +int HDF5Handler::getMaxID() +{ + std::vector<lvl::Room>& roomsList = m_Level.getRooms(); + lvl::Room lastRoom = roomsList.back(); + return lastRoom.getId(); +} + +} \ No newline at end of file diff --git a/editor/src/HDF5Handler.hpp b/editor/src/HDF5Handler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4000cce8b9f0034a84d9496afe0e134dc984f691 --- /dev/null +++ b/editor/src/HDF5Handler.hpp @@ -0,0 +1,56 @@ +#pragma once +#include <QImage> +#include <QPixmap> +#include <level.hpp> +#include <room.hpp> +#include "TileBar.hpp" +#include <QMessageBox> + +namespace editor +{ + +class HDF5Handler +{ + +public: + /** + * @brief Create a new HDF5Handler (main interface with liblvl library) + */ + HDF5Handler(); + + /** + * @brief Create a new HDF5Handler (main interface with liblvl library) + */ + HDF5Handler(std::filesystem::path path); + + /** + * @brief destructor for HDF5Handler, default + */ + ~HDF5Handler() = default; + + /** + * @brief loads the tilesheet and puts tiles into TileBar + * @param tileBar pointer to the TileBar to show the tiles in + */ + void loadTilesheet(TileBar* tileBar) const; + + /** + * @brief saves configured room to HDF5 + * @param id ID of the room, has to be unique! + * @param name Name of the room + * @param tileIDs 2D QVector of the tileIDs + * @param mobIDs 2D QVector of the tileIDs + */ + void saveRoom(int id, QString name, QVector<QVector<int>> tileIDs, QVector<QVector<int>> mobIDs); + + /** + * @brief find maximum room-ID in current HDF5-file + * @return highest room-ID + */ + int getMaxID(); + +private: + lvl::Level m_Level; +}; + +} // editor \ No newline at end of file diff --git a/editor/src/MainWindow.cpp b/editor/src/MainWindow.cpp index bf0ed0ad41e25abcbbe083b54dc8954fc90a5c28..9451217cef6f15c4a83f5f3f67cdbf2991554e89 100644 --- a/editor/src/MainWindow.cpp +++ b/editor/src/MainWindow.cpp @@ -16,10 +16,24 @@ MainWindow::MainWindow(DialogSelection selected, const std::filesystem::path& pa QWidget* centralWidget = new QWidget(this); QHBoxLayout* mainLayout = new QHBoxLayout; + if (QFile::exists("./level.h5")) + { + std::filesystem::path path = "./level.h5"; + HDF5Handler handler = HDF5Handler(path); + m_ID = handler.getMaxID() + 1; + std::cout << m_ID << std::endl; + } else + { + m_ID = 2; + } + // Create the menu bar QMenuBar* menuBar = new QMenuBar(this); QMenu* fileMenu = menuBar->addMenu("File"); - QMenu* settingsMenu = menuBar->addMenu("Settings"); + //QMenu* settingsMenu = menuBar->addMenu("Settings"); + QAction* saveRoomAction = new QAction("Save Room", this); + connect(saveRoomAction, &QAction::triggered, this, &MainWindow::saveLevel); + fileMenu->addAction(saveRoomAction); QAction* quitAction = new QAction("Quit", this); connect(quitAction, &QAction::triggered, this, &MainWindow::close); fileMenu->addAction(quitAction); @@ -31,15 +45,8 @@ MainWindow::MainWindow(DialogSelection selected, const std::filesystem::path& pa m_leftWidget = leftWidget; connect(leftWidget, &editor::TileBar::itemClicked, this, &MainWindow::handleTileBarClick); - //temporary example, replace with real list of tileset - QStringList itemsLeft; - QList<QPixmap> pixmapsLeft; - for (int i = 1; i <= 100; ++i) - { - itemsLeft << QString("Item %1").arg(i); - pixmapsLeft << QPixmap("./editor/assets/images.png"); - } - leftWidget->populateList(itemsLeft, pixmapsLeft); + const HDF5Handler handler; + handler.loadTilesheet(m_leftWidget); // Center grid CenterGrid* middleWidget = new CenterGrid(this); @@ -72,9 +79,6 @@ MainWindow::MainWindow(DialogSelection selected, const std::filesystem::path& pa centralWidget->setLayout(mainLayout); setCentralWidget(centralWidget); - //testing centerGrid buttons - middleWidget->setCurrentSprite(QString::fromStdString("from MainWindow")); - //initialize middleWidget as fully custom board middleWidget->drawPreset(5); } @@ -83,7 +87,7 @@ void MainWindow::handleTileBarClick(int index, int id) { if (id == 0) { - m_centerGrid->setCurrentSprite(m_leftWidget->getPixmapByIndex(index)); + m_centerGrid->setCurrentSprite(m_leftWidget->getPixmapByIndex(index), index); } else { QMessageBox::StandardButton confirmationPopup; @@ -100,5 +104,26 @@ void MainWindow::handleTileBarClick(int index, int id) } } +void MainWindow::saveLevel() +{ + QVector<QVector<int>> tileIDs = m_centerGrid->getTileIDs(); + QVector<QVector<int>> mobIDs; + QString name = "testlevel1234"; + + if (QFile::exists("./level.h5")) + { + std::cout << "using new handler" << std::endl; + std::filesystem::path path = "./level.h5"; + HDF5Handler handler = HDF5Handler(path); + handler.saveRoom(m_ID, name, tileIDs, mobIDs); + } else + { + std::cout << "using default handler" << std::endl; + HDF5Handler handler = HDF5Handler(); + handler.saveRoom(m_ID, name, tileIDs, mobIDs); + } + m_ID++; +} + } diff --git a/editor/src/MainWindow.hpp b/editor/src/MainWindow.hpp index de730ae106bde7d3875903baf6869a909407962f..adb32c0f47cbea46b02771433a649cf14d1220ae 100644 --- a/editor/src/MainWindow.hpp +++ b/editor/src/MainWindow.hpp @@ -13,6 +13,7 @@ #include "StartupDialog.hpp" #include "CenterGrid.hpp" #include "TileBar.hpp" +#include "HDF5Handler.hpp" namespace editor @@ -42,6 +43,18 @@ private slots: void handleTileBarClick(int index, int id); private: + + /** + * @brief Saves room to HDF5 when called in menu + */ + void saveLevel(); + + /** + * @brief Converts 2D QVector to 1D std::vector for saving + * @return std::vector<int> 1D std::vector with tileIDs that can be saved in HDF5 + */ + std::vector<int> flatten(const QVector<QVector<int>>& input); + /** * @brief Pointer to the centerGrid */ @@ -52,6 +65,11 @@ private: */ TileBar* m_leftWidget; + /** + * @brief Room ID to use for saving next room + */ + int m_ID; + }; } // editor