diff --git a/data/test2.material b/data/test2.material new file mode 100644 index 0000000..1cf5613 --- /dev/null +++ b/data/test2.material @@ -0,0 +1,4 @@ +{ + "albedoTexture": "", + "color": "1,0,0.0156863" +} diff --git a/include/assetmanager.h b/include/assetmanager.h index 23d3670..1f48f05 100644 --- a/include/assetmanager.h +++ b/include/assetmanager.h @@ -11,10 +11,10 @@ public: void setRenderer(Renderer* r) { renderer = r; } - + MeshAsset* loadMesh(const std::string& path); MaterialAsset* loadMaterial(const std::string& path); - + private: Renderer* renderer = nullptr; }; diff --git a/src/assetmanager.cpp b/src/assetmanager.cpp index 9bbb163..944a5d8 100644 --- a/src/assetmanager.cpp +++ b/src/assetmanager.cpp @@ -50,7 +50,13 @@ MeshAsset* AssetManager::loadMesh(const std::string& path) { } MaterialAsset* AssetManager::loadMaterial(const std::string& path) { - std::ifstream file("data/" + path); + std::string fixedPath; + if(path[0] != '/') // then this is an absolute path, and we absolutely do not want to mess with that + fixedPath = "data/" + path; + else + fixedPath = path; + + std::ifstream file(fixedPath); if(!file) return nullptr; diff --git a/tools/materialeditor/include/mainwindow.h b/tools/materialeditor/include/mainwindow.h index 1b41e7d..2a91d1e 100644 --- a/tools/materialeditor/include/mainwindow.h +++ b/tools/materialeditor/include/mainwindow.h @@ -2,14 +2,32 @@ #include #include +#include +#include struct Context; +struct MeshComponent; class MainWindow : public QMainWindow { public: MainWindow(Context& context); + ~MainWindow(); private: + void openMaterial(QString path); + void saveMaterial(QString path); + + void updateControls(); + + QStringList openedFiles; + + QAction* saveAction, *saveAsAction, *openRecentAction; + + QString currentlyOpenMaterial; + MeshComponent* meshComponent; + + QGridLayout* attributesLayout; + Context& context; QVulkanInstance* instance = nullptr; }; diff --git a/tools/materialeditor/src/mainwindow.cpp b/tools/materialeditor/src/mainwindow.cpp index 8da324a..c49f35a 100644 --- a/tools/materialeditor/src/mainwindow.cpp +++ b/tools/materialeditor/src/mainwindow.cpp @@ -6,8 +6,11 @@ #include #include #include -#include #include +#include +#include +#include +#include #include "renderwindow.h" #include "renderer.h" @@ -15,11 +18,15 @@ #include "ecs.h" #include "worldmanager.h" #include "material.h" +#include "assetmanager.h" MainWindow::MainWindow(Context& context) : context(context) { - setWindowTitle("Material Editor"); resize(1280, 720); + QSettings settings; + if(!settings.value("recentlyOpened").isNull()) + openedFiles = settings.value("recentlyOpened").toStringList(); + QMenuBar* mainMenuBar = new QMenuBar(); setMenuBar(mainMenuBar); @@ -30,26 +37,47 @@ MainWindow::MainWindow(Context& context) : context(context) { { QAction* newAction = new QAction("New"); newAction->setIcon(QIcon::fromTheme("document-new")); + connect(newAction, &QAction::triggered, [this] { + openMaterial("basic.material"); + currentlyOpenMaterial = "new material"; + }); newAction->setShortcut(QKeySequence("CTRL+N")); fileMenu->addAction(newAction); QAction* openAction = new QAction("Open"); + connect(openAction, &QAction::triggered, [this] { + QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), + "../data/", + tr("Material Files (*.material)")); + if(!fileName.isEmpty()) + openMaterial(fileName); + }); openAction->setIcon(QIcon::fromTheme("document-open")); openAction->setShortcut(QKeySequence("CTRL+O")); fileMenu->addAction(openAction); - QAction* openRecentAction = new QAction("Open Recent..."); + openRecentAction = new QAction("Open Recent..."); openRecentAction->setIcon(QIcon::fromTheme("document-open-recent")); fileMenu->addAction(openRecentAction); fileMenu->addSeparator(); - QAction* saveAction = new QAction("Save"); + saveAction = new QAction("Save"); + connect(saveAction, &QAction::triggered, [this] { + saveMaterial(currentlyOpenMaterial); + }); saveAction->setIcon(QIcon::fromTheme("document-save")); saveAction->setShortcut(QKeySequence("CTRL+S")); fileMenu->addAction(saveAction); - QAction* saveAsAction = new QAction("Save As..."); + saveAsAction = new QAction("Save As..."); + connect(saveAsAction, &QAction::triggered, [this] { + QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), + "../data/", + tr("Material Files (*.material)")); + if(!fileName.isEmpty()) + saveMaterial(fileName); + }); saveAsAction->setIcon(QIcon::fromTheme("document-save-as")); saveAsAction->setShortcut(QKeySequence("CTRL+SHIFT+S")); fileMenu->addAction(saveAsAction); @@ -69,7 +97,7 @@ MainWindow::MainWindow(Context& context) : context(context) { QHBoxLayout* layout = new QHBoxLayout(); centralWidget->setLayout(layout); - QGridLayout* attributesLayout = new QGridLayout(); + attributesLayout = new QGridLayout(); attributesLayout->setAlignment(Qt::AlignTop); attributesLayout->setSpacing(0); layout->addLayout(attributesLayout); @@ -80,9 +108,7 @@ MainWindow::MainWindow(Context& context) : context(context) { auto meshComponents = ECS::getWorldComponents(worldManager.getCurrentWorld()); auto& [id, mesh] = meshComponents[0]; - - ColorEdit* colorEdit = new ColorEdit(mesh->material->color); - attributesLayout->addWidget(colorEdit, 0, 1); + meshComponent = mesh; instance = new QVulkanInstance(); instance->setVkInstance(context.renderer->getInstance()); @@ -93,5 +119,85 @@ MainWindow::MainWindow(Context& context) : context(context) { QWidget* wrapper = QWidget::createWindowContainer(window); layout->addWidget(wrapper); + + updateControls(); +} + +MainWindow::~MainWindow() { + QSettings settings; + settings.setValue("recentlyOpened", openedFiles); +} + +void MainWindow::openMaterial(QString path) { + currentlyOpenMaterial = path; + + meshComponent->material = assetManager.loadMaterial(path.toStdString()); + + ColorEdit* colorEdit = new ColorEdit(meshComponent->material->color); + attributesLayout->addWidget(colorEdit, 0, 1); + + if(openedFiles.contains(path)) + openedFiles.removeOne(path); + + openedFiles.push_back(path); + + updateControls(); +} + +void MainWindow::saveMaterial(QString path) { + MaterialAsset* material = meshComponent->material; + + QString color; + color = QString::number(material->color.x) + "," + QString::number(material->color.y) + "," + QString::number(material->color.z); + + QJsonObject object { + {"albedoTexture", material->albedoTexturePath.c_str()}, + {"color", color} + }; + + QJsonDocument document(object); + + QFile jsonFile(path); + jsonFile.open(QFile::WriteOnly); + jsonFile.write(document.toJson()); + + currentlyOpenMaterial = path; +} + +void MainWindow::updateControls() { + if(!currentlyOpenMaterial.isEmpty()) + setWindowTitle("Material Editor - " + currentlyOpenMaterial); + else + setWindowTitle("Material Editor"); + + saveAction->setEnabled(!currentlyOpenMaterial.isEmpty()); + saveAsAction->setEnabled(!currentlyOpenMaterial.isEmpty()); + + if(!openedFiles.empty()) { + QMenu* recentlyOpenedMenu = new QMenu(); + for(auto file : openedFiles) { + QAction* fileAction = new QAction(file); + connect(fileAction, &QAction::triggered, [this, file] { + openMaterial(file); + }); + fileAction->setIcon(QIcon("data/maticon.png")); + recentlyOpenedMenu->addAction(fileAction); + } + + recentlyOpenedMenu->addSeparator(); + + QAction* clearRecentAction = new QAction("Clear"); + connect(clearRecentAction, &QAction::triggered, [this] { + openedFiles.clear(); + updateControls(); + }); + clearRecentAction->setIcon(QIcon::fromTheme("edit-clear")); + recentlyOpenedMenu->addAction(clearRecentAction); + + openRecentAction->setEnabled(true); + openRecentAction->setMenu(recentlyOpenedMenu); + } else { + openRecentAction->setEnabled(false); + } }