Make material editor functional
This commit is contained in:
parent
4a01dab006
commit
09b6d59cf9
5 changed files with 146 additions and 12 deletions
4
data/test2.material
Normal file
4
data/test2.material
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"albedoTexture": "",
|
||||||
|
"color": "1,0,0.0156863"
|
||||||
|
}
|
|
@ -11,10 +11,10 @@ public:
|
||||||
void setRenderer(Renderer* r) {
|
void setRenderer(Renderer* r) {
|
||||||
renderer = r;
|
renderer = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshAsset* loadMesh(const std::string& path);
|
MeshAsset* loadMesh(const std::string& path);
|
||||||
MaterialAsset* loadMaterial(const std::string& path);
|
MaterialAsset* loadMaterial(const std::string& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Renderer* renderer = nullptr;
|
Renderer* renderer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,13 @@ MeshAsset* AssetManager::loadMesh(const std::string& path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialAsset* AssetManager::loadMaterial(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)
|
if(!file)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,32 @@
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QVulkanInstance>
|
#include <QVulkanInstance>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
struct Context;
|
struct Context;
|
||||||
|
struct MeshComponent;
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
public:
|
public:
|
||||||
MainWindow(Context& context);
|
MainWindow(Context& context);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
private:
|
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;
|
Context& context;
|
||||||
QVulkanInstance* instance = nullptr;
|
QVulkanInstance* instance = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QVulkanWindow>
|
#include <QVulkanWindow>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QGridLayout>
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
#include "renderwindow.h"
|
#include "renderwindow.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
@ -15,11 +18,15 @@
|
||||||
#include "ecs.h"
|
#include "ecs.h"
|
||||||
#include "worldmanager.h"
|
#include "worldmanager.h"
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
|
#include "assetmanager.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(Context& context) : context(context) {
|
MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
setWindowTitle("Material Editor");
|
|
||||||
resize(1280, 720);
|
resize(1280, 720);
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
if(!settings.value("recentlyOpened").isNull())
|
||||||
|
openedFiles = settings.value("recentlyOpened").toStringList();
|
||||||
|
|
||||||
QMenuBar* mainMenuBar = new QMenuBar();
|
QMenuBar* mainMenuBar = new QMenuBar();
|
||||||
setMenuBar(mainMenuBar);
|
setMenuBar(mainMenuBar);
|
||||||
|
|
||||||
|
@ -30,26 +37,47 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
{
|
{
|
||||||
QAction* newAction = new QAction("New");
|
QAction* newAction = new QAction("New");
|
||||||
newAction->setIcon(QIcon::fromTheme("document-new"));
|
newAction->setIcon(QIcon::fromTheme("document-new"));
|
||||||
|
connect(newAction, &QAction::triggered, [this] {
|
||||||
|
openMaterial("basic.material");
|
||||||
|
currentlyOpenMaterial = "new material";
|
||||||
|
});
|
||||||
newAction->setShortcut(QKeySequence("CTRL+N"));
|
newAction->setShortcut(QKeySequence("CTRL+N"));
|
||||||
fileMenu->addAction(newAction);
|
fileMenu->addAction(newAction);
|
||||||
|
|
||||||
QAction* openAction = new QAction("Open");
|
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->setIcon(QIcon::fromTheme("document-open"));
|
||||||
openAction->setShortcut(QKeySequence("CTRL+O"));
|
openAction->setShortcut(QKeySequence("CTRL+O"));
|
||||||
fileMenu->addAction(openAction);
|
fileMenu->addAction(openAction);
|
||||||
|
|
||||||
QAction* openRecentAction = new QAction("Open Recent...");
|
openRecentAction = new QAction("Open Recent...");
|
||||||
openRecentAction->setIcon(QIcon::fromTheme("document-open-recent"));
|
openRecentAction->setIcon(QIcon::fromTheme("document-open-recent"));
|
||||||
fileMenu->addAction(openRecentAction);
|
fileMenu->addAction(openRecentAction);
|
||||||
|
|
||||||
fileMenu->addSeparator();
|
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->setIcon(QIcon::fromTheme("document-save"));
|
||||||
saveAction->setShortcut(QKeySequence("CTRL+S"));
|
saveAction->setShortcut(QKeySequence("CTRL+S"));
|
||||||
fileMenu->addAction(saveAction);
|
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->setIcon(QIcon::fromTheme("document-save-as"));
|
||||||
saveAsAction->setShortcut(QKeySequence("CTRL+SHIFT+S"));
|
saveAsAction->setShortcut(QKeySequence("CTRL+SHIFT+S"));
|
||||||
fileMenu->addAction(saveAsAction);
|
fileMenu->addAction(saveAsAction);
|
||||||
|
@ -69,7 +97,7 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
QHBoxLayout* layout = new QHBoxLayout();
|
QHBoxLayout* layout = new QHBoxLayout();
|
||||||
centralWidget->setLayout(layout);
|
centralWidget->setLayout(layout);
|
||||||
|
|
||||||
QGridLayout* attributesLayout = new QGridLayout();
|
attributesLayout = new QGridLayout();
|
||||||
attributesLayout->setAlignment(Qt::AlignTop);
|
attributesLayout->setAlignment(Qt::AlignTop);
|
||||||
attributesLayout->setSpacing(0);
|
attributesLayout->setSpacing(0);
|
||||||
layout->addLayout(attributesLayout);
|
layout->addLayout(attributesLayout);
|
||||||
|
@ -80,9 +108,7 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
auto meshComponents = ECS::getWorldComponents<MeshComponent>(worldManager.getCurrentWorld());
|
auto meshComponents = ECS::getWorldComponents<MeshComponent>(worldManager.getCurrentWorld());
|
||||||
|
|
||||||
auto& [id, mesh] = meshComponents[0];
|
auto& [id, mesh] = meshComponents[0];
|
||||||
|
meshComponent = mesh;
|
||||||
ColorEdit* colorEdit = new ColorEdit(mesh->material->color);
|
|
||||||
attributesLayout->addWidget(colorEdit, 0, 1);
|
|
||||||
|
|
||||||
instance = new QVulkanInstance();
|
instance = new QVulkanInstance();
|
||||||
instance->setVkInstance(context.renderer->getInstance());
|
instance->setVkInstance(context.renderer->getInstance());
|
||||||
|
@ -93,5 +119,85 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
|
|
||||||
QWidget* wrapper = QWidget::createWindowContainer(window);
|
QWidget* wrapper = QWidget::createWindowContainer(window);
|
||||||
layout->addWidget(wrapper);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue