Files
Seele/src/Editor/Asset/MaterialLoader.cpp
T

261 lines
11 KiB
C++
Raw Normal View History

2020-06-02 11:46:18 +02:00
#include "MaterialLoader.h"
2024-06-09 12:20:04 +02:00
#include "Asset/AssetRegistry.h"
#include "Asset/MaterialAsset.h"
#include "Asset/TextureAsset.h"
2020-06-02 11:46:18 +02:00
#include "Graphics/Graphics.h"
2023-11-15 17:42:57 +01:00
#include "Graphics/Shader.h"
2023-01-21 18:43:21 +01:00
#include "Material/Material.h"
#include "Material/ShaderExpression.h"
2024-06-09 12:20:04 +02:00
#include "Window/WindowManager.h"
2024-01-16 19:24:49 +01:00
#include <fmt/core.h>
#include <fstream>
2024-06-09 12:20:04 +02:00
#include <iostream>
#include <nlohmann/json.hpp>
2020-06-02 11:46:18 +02:00
using namespace Seele;
2023-01-21 18:43:21 +01:00
using json = nlohmann::json;
2020-06-02 11:46:18 +02:00
2024-06-09 12:20:04 +02:00
MaterialLoader::MaterialLoader(Gfx::PGraphics graphics) : graphics(graphics) {
2023-11-05 10:36:01 +01:00
OMaterialAsset placeholderAsset = new MaterialAsset();
2024-06-09 12:20:04 +02:00
import(
MaterialImportArgs{
.filePath = std::filesystem::absolute("./shaders/Placeholder.json"),
.importPath = "",
},
placeholderAsset);
2023-11-05 10:36:01 +01:00
AssetRegistry::get().assetRoot->materials[""] = std::move(placeholderAsset);
2020-06-02 11:46:18 +02:00
}
2024-06-09 12:20:04 +02:00
MaterialLoader::~MaterialLoader() {}
2020-06-02 11:46:18 +02:00
2024-06-09 12:20:04 +02:00
void MaterialLoader::importAsset(MaterialImportArgs args) {
2023-02-01 22:13:04 +01:00
std::filesystem::path assetPath = args.filePath.filename();
2021-11-11 20:12:50 +01:00
assetPath.replace_extension("asset");
2023-11-05 10:36:01 +01:00
OMaterialAsset asset = new MaterialAsset(args.importPath, assetPath.stem().string());
2021-11-11 20:12:50 +01:00
asset->setStatus(Asset::Status::Loading);
2023-11-05 10:36:01 +01:00
PMaterialAsset ref = asset;
AssetRegistry::get().registerMaterial(std::move(asset));
import(args, ref);
2021-11-11 20:12:50 +01:00
}
2024-06-09 12:20:04 +02:00
void MaterialLoader::import(MaterialImportArgs args, PMaterialAsset asset) {
2023-07-31 21:43:20 +02:00
auto jsonstream = std::ifstream(args.filePath.c_str());
2023-01-21 18:43:21 +01:00
json j;
2023-07-31 21:43:20 +02:00
jsonstream >> j;
2023-01-21 18:43:21 +01:00
std::string materialName = j["name"].get<std::string>() + "Material";
2024-04-19 18:23:36 +02:00
Gfx::ODescriptorLayout layout = graphics->createDescriptorLayout("pMaterial");
2024-06-09 12:20:04 +02:00
// Shader file needs to conform to the slang standard, which prohibits _
2023-01-21 18:43:21 +01:00
materialName.erase(std::remove(materialName.begin(), materialName.end(), '_'), materialName.end());
2023-11-27 22:50:37 +01:00
materialName.erase(std::remove(materialName.begin(), materialName.end(), '-'), materialName.end());
2023-01-21 18:43:21 +01:00
uint32 uniformBufferOffset = 0;
uint32 bindingCounter = 0; // Uniform buffers are always binding 0
2023-11-06 14:47:21 +01:00
int32 uniformBinding = -1;
2023-11-11 22:39:17 +01:00
Array<OShaderExpression> expressions;
2023-11-05 10:36:01 +01:00
uint32 key = 0;
uint32 auxKey = 0;
Array<std::string> parameters;
2024-06-09 12:20:04 +02:00
for (auto& param : j["params"].items()) {
2023-01-21 18:43:21 +01:00
std::string type = param.value()["type"].get<std::string>();
auto defaultValue = param.value().find("default");
// TODO: ALIGNMENT RULES
2024-06-09 12:20:04 +02:00
if (type.compare("float") == 0) {
2024-05-01 14:10:52 +02:00
float defaultData = 0.f;
2024-06-09 12:20:04 +02:00
if (defaultValue != param.value().end()) {
2024-05-01 14:10:52 +02:00
defaultData = std::stof(defaultValue.value().get<std::string>());
}
OFloatParameter p = new FloatParameter(param.key(), defaultData, uniformBufferOffset, uniformBinding);
2024-06-09 12:20:04 +02:00
if (uniformBinding == -1) {
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = bindingCounter,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
});
2023-01-21 18:43:21 +01:00
uniformBinding = bindingCounter++;
}
uniformBufferOffset += 4;
2023-11-05 10:36:01 +01:00
parameters.add(p->key);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2023-01-21 18:43:21 +01:00
}
// TODO: ALIGNMENT RULES
2024-06-09 12:20:04 +02:00
else if (type.compare("float3") == 0) {
2024-05-01 14:10:52 +02:00
Vector defaultData = Vector(0, 0, 0);
2024-06-09 12:20:04 +02:00
if (defaultValue != param.value().end()) {
2024-05-01 14:10:52 +02:00
defaultData = parseVector(defaultValue.value().get<std::string>().c_str());
}
OVectorParameter p = new VectorParameter(param.key(), defaultData, uniformBufferOffset, uniformBinding);
2024-06-09 12:20:04 +02:00
if (uniformBinding == -1) {
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = bindingCounter,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
});
2023-01-21 18:43:21 +01:00
uniformBinding = bindingCounter++;
}
2024-05-01 14:10:52 +02:00
uniformBufferOffset += 16;
2024-06-09 12:20:04 +02:00
parameters.add(p->key);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2024-06-09 12:20:04 +02:00
} else if (type.compare("Texture2D") == 0) {
2024-05-01 14:10:52 +02:00
PTextureAsset texture;
2024-06-09 12:20:04 +02:00
if (defaultValue != param.value().end()) {
2023-01-21 18:43:21 +01:00
std::string defaultString = defaultValue.value().get<std::string>();
2024-05-01 14:10:52 +02:00
auto slashPos = defaultString.rfind("/");
std::string folder = "";
2024-06-09 12:20:04 +02:00
if (slashPos != std::string::npos) {
2024-05-01 14:10:52 +02:00
folder = defaultString.substr(0, slashPos - 1);
defaultString = defaultString.substr(slashPos, defaultString.length());
}
texture = AssetRegistry::findTexture(folder, defaultString);
2023-01-21 18:43:21 +01:00
}
2024-06-09 12:20:04 +02:00
if (texture == nullptr) {
2024-05-01 14:10:52 +02:00
texture = AssetRegistry::findTexture("", ""); // this will return placeholder texture
2023-01-21 18:43:21 +01:00
}
2024-05-01 14:10:52 +02:00
OTextureParameter p = new TextureParameter(param.key(), texture, bindingCounter);
2024-06-09 12:20:04 +02:00
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = bindingCounter++,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
});
2023-11-05 10:36:01 +01:00
parameters.add(p->key);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2024-06-09 12:20:04 +02:00
} else if (type.compare("Sampler") == 0) {
2024-05-01 14:10:52 +02:00
OSamplerParameter p = new SamplerParameter(param.key(), graphics->createSampler({}), bindingCounter);
2024-06-09 12:20:04 +02:00
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = bindingCounter++,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
});
2023-11-05 10:36:01 +01:00
parameters.add(p->key);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2024-06-09 12:20:04 +02:00
} else if (type.compare("Sampler2D") == 0) {
2024-05-01 14:10:52 +02:00
PTextureAsset texture;
2024-06-09 12:20:04 +02:00
if (defaultValue != param.value().end()) {
2024-04-26 11:42:28 +02:00
std::string defaultString = defaultValue.value().get<std::string>();
2024-05-01 14:10:52 +02:00
auto slashPos = defaultString.rfind("/");
std::string folder = "";
2024-06-09 12:20:04 +02:00
if (slashPos != std::string::npos) {
2024-05-01 14:10:52 +02:00
folder = defaultString.substr(0, slashPos - 1);
defaultString = defaultString.substr(slashPos, defaultString.length());
}
texture = AssetRegistry::findTexture(folder, defaultString);
2024-04-26 11:42:28 +02:00
}
2024-06-09 12:20:04 +02:00
if (texture == nullptr) {
2024-05-01 14:10:52 +02:00
texture = AssetRegistry::findTexture("", ""); // this will return placeholder texture
2024-04-26 11:42:28 +02:00
}
2024-05-01 14:10:52 +02:00
OCombinedTextureParameter p = new CombinedTextureParameter(param.key(), texture, graphics->createSampler({}), bindingCounter);
2024-06-09 12:20:04 +02:00
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = bindingCounter++,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
});
2024-04-26 11:42:28 +02:00
parameters.add(p->key);
expressions.add(std::move(p));
2024-06-09 12:20:04 +02:00
} else {
2023-01-21 18:43:21 +01:00
std::cout << "Error unsupported parameter type" << std::endl;
}
}
uint32 uniformDataSize = uniformBufferOffset;
2024-06-09 12:20:04 +02:00
auto referenceExpression = [&parameters, &auxKey, &expressions](json obj) -> std::string {
if (obj.is_string()) {
2023-11-05 10:36:01 +01:00
std::string str = obj.get<std::string>();
2024-06-09 12:20:04 +02:00
if (parameters.find(str) != parameters.end()) {
2024-04-26 10:28:34 +02:00
return str;
}
2023-11-05 10:36:01 +01:00
OConstantExpression c = new ConstantExpression(str, ExpressionType::UNKNOWN);
2024-01-16 19:24:49 +01:00
std::string name = fmt::format("const_{0}", auxKey++);
2023-11-05 10:36:01 +01:00
c->key = name;
2023-11-11 22:39:17 +01:00
expressions.add(std::move(c));
2023-11-05 10:36:01 +01:00
return name;
2024-06-09 12:20:04 +02:00
} else {
2024-01-16 19:24:49 +01:00
return fmt::format("{0}", obj.get<uint32>());
2023-02-24 22:09:07 +01:00
}
};
MaterialNode mat;
2024-06-09 12:20:04 +02:00
for (auto& param : j["code"].items()) {
2023-11-05 10:36:01 +01:00
auto& obj = param.value();
2023-02-24 22:09:07 +01:00
std::string exp = obj["exp"].get<std::string>();
2024-06-09 12:20:04 +02:00
if (exp.compare("Const") == 0) {
2023-12-03 00:29:02 +01:00
OConstantExpression p = new ConstantExpression();
2024-01-16 19:24:49 +01:00
std::string name = fmt::format("{0}", key++);
2023-12-03 00:29:02 +01:00
p->key = name;
p->expr = obj["value"];
expressions.add(std::move(p));
}
2024-06-09 12:20:04 +02:00
if (exp.compare("Add") == 0) {
2023-11-05 10:36:01 +01:00
OAddExpression p = new AddExpression();
2024-01-16 19:24:49 +01:00
std::string name = fmt::format("{0}", key++);
2023-11-05 10:36:01 +01:00
p->key = name;
p->inputs["lhs"].source = referenceExpression(obj["lhs"]);
p->inputs["rhs"].source = referenceExpression(obj["rhs"]);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2023-02-24 22:09:07 +01:00
}
2024-06-09 12:20:04 +02:00
if (exp.compare("Sub") == 0) {
2023-11-05 10:36:01 +01:00
OSubExpression p = new SubExpression();
2024-01-16 19:24:49 +01:00
std::string name = fmt::format("{0}", key++);
2023-11-05 10:36:01 +01:00
p->key = name;
p->inputs["lhs"].source = referenceExpression(obj["lhs"]);
p->inputs["rhs"].source = referenceExpression(obj["rhs"]);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2023-02-24 22:09:07 +01:00
}
2024-06-09 12:20:04 +02:00
if (exp.compare("Mul") == 0) {
2023-11-05 10:36:01 +01:00
OMulExpression p = new MulExpression();
2024-01-16 19:24:49 +01:00
std::string name = fmt::format("{0}", key++);
2023-11-05 10:36:01 +01:00
p->key = name;
p->inputs["lhs"].source = referenceExpression(obj["lhs"]);
p->inputs["rhs"].source = referenceExpression(obj["rhs"]);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2023-02-24 22:09:07 +01:00
}
2024-06-09 12:20:04 +02:00
if (exp.compare("Swizzle") == 0) {
2023-11-05 10:36:01 +01:00
OSwizzleExpression p = new SwizzleExpression();
2024-01-16 19:24:49 +01:00
std::string name = fmt::format("{0}", key++);
2023-11-05 10:36:01 +01:00
p->key = name;
p->inputs["target"].source = referenceExpression(obj["target"]);
2023-02-24 22:09:07 +01:00
int32 i = 0;
2024-06-09 12:20:04 +02:00
for (auto& c : obj["comp"].items()) {
2023-02-24 22:09:07 +01:00
p->comp[i++] = c.value().get<uint32>();
}
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2023-02-24 22:09:07 +01:00
}
2024-06-09 12:20:04 +02:00
if (exp.compare("Sample") == 0) {
2023-11-05 10:36:01 +01:00
OSampleExpression p = new SampleExpression();
2024-01-16 19:24:49 +01:00
std::string name = fmt::format("{0}", key++);
2023-11-05 10:36:01 +01:00
p->key = name;
2024-06-09 12:20:04 +02:00
if (obj.contains("texture")) {
2024-04-26 11:42:28 +02:00
p->inputs["texture"].source = referenceExpression(obj["texture"]);
}
2023-11-05 10:36:01 +01:00
p->inputs["sampler"].source = referenceExpression(obj["sampler"]);
p->inputs["coords"].source = referenceExpression(obj["coords"]);
2023-11-11 22:39:17 +01:00
expressions.add(std::move(p));
2023-02-24 22:09:07 +01:00
}
2024-06-09 12:20:04 +02:00
if (exp.compare("BRDF") == 0) {
2023-02-24 22:09:07 +01:00
mat.profile = obj["profile"].get<std::string>();
2024-06-09 12:20:04 +02:00
for (auto& val : obj["values"].items()) {
2023-11-06 14:47:21 +01:00
mat.variables[val.key()] = referenceExpression(val.value());
2023-02-24 22:09:07 +01:00
}
}
}
2023-01-21 18:43:21 +01:00
layout->create();
2024-06-09 12:20:04 +02:00
asset->material = new Material(graphics, std::move(layout), uniformDataSize, uniformBinding, materialName, std::move(expressions),
std::move(parameters), std::move(mat));
2023-07-31 21:43:20 +02:00
2023-02-24 22:09:07 +01:00
asset->material->compile();
2023-01-21 18:43:21 +01:00
graphics->getShaderCompiler()->registerMaterial(asset->material);
asset->setStatus(Asset::Status::Ready);
2023-07-31 21:43:20 +02:00
2024-06-09 12:20:04 +02:00
if (asset->getName().empty()) {
2023-07-31 21:43:20 +02:00
return;
}
2024-06-09 12:20:04 +02:00
auto stream = AssetRegistry::createWriteStream((std::filesystem::path(asset->folderPath) / asset->getName()).string().append(".asset"),
std::ios::binary);
2023-07-31 21:43:20 +02:00
ArchiveBuffer archive;
Serialization::save(archive, MaterialAsset::IDENTIFIER);
Serialization::save(archive, asset->getName());
Serialization::save(archive, asset->getFolderPath());
asset->save(archive);
archive.writeToStream(stream);
2022-04-15 23:45:44 +02:00
////co_return;
2020-06-02 11:46:18 +02:00
}
2020-10-03 11:00:10 +02:00
2024-06-09 12:20:04 +02:00
PMaterialAsset MaterialLoader::getPlaceHolderMaterial() { return placeholderMaterial; }